From e0f639ca2c2d3a7021d61d2f2ae96feef80e6a05 Mon Sep 17 00:00:00 2001 From: "Taehoon Moon (Bot)" Date: Sun, 11 Aug 2024 11:41:59 +0000 Subject: [PATCH] Publish Docs - 0.16.0 --- docs/0.16.0/.nojekyll | 0 docs/0.16.0/404.html | 17 ++ docs/0.16.0/assets/css/styles.1b097026.css | 1 + ...nsert-7dfbb3a9123d4aa47b845b7dede97dc9.jpg | Bin 0 -> 363481 bytes ...rcase-1be5ced205cee0d2eeb56af1591440ac.jpg | Bin 0 -> 67868 bytes docs/0.16.0/assets/js/007e0817.64d185e0.js | 1 + docs/0.16.0/assets/js/017e736e.f5dc6055.js | 1 + docs/0.16.0/assets/js/01a12966.469b19f8.js | 1 + docs/0.16.0/assets/js/01a85c17.de44d5e4.js | 1 + docs/0.16.0/assets/js/02aa4531.17b335fe.js | 1 + docs/0.16.0/assets/js/02bfc02d.c93d2576.js | 1 + docs/0.16.0/assets/js/037683de.b9938f31.js | 1 + docs/0.16.0/assets/js/045be9fd.bc59c80a.js | 1 + docs/0.16.0/assets/js/0544f90b.ccc9e299.js | 1 + docs/0.16.0/assets/js/06322d53.4d22d233.js | 1 + docs/0.16.0/assets/js/07294b24.663c5d97.js | 1 + docs/0.16.0/assets/js/078a6308.4d53bdee.js | 1 + docs/0.16.0/assets/js/0b621d16.b92732eb.js | 1 + docs/0.16.0/assets/js/0c18287f.2d4dde49.js | 1 + docs/0.16.0/assets/js/0c94c658.a5f781c3.js | 1 + docs/0.16.0/assets/js/0ea64360.3dae4181.js | 1 + docs/0.16.0/assets/js/104749c9.09fc621f.js | 1 + docs/0.16.0/assets/js/107910e9.5dfe754c.js | 1 + docs/0.16.0/assets/js/15868c40.654d0d37.js | 1 + docs/0.16.0/assets/js/160faf1d.05a9000e.js | 1 + docs/0.16.0/assets/js/16682cd3.e744db6a.js | 1 + docs/0.16.0/assets/js/16815c2a.9ebfe213.js | 1 + docs/0.16.0/assets/js/1774.e76e375b.js | 1 + docs/0.16.0/assets/js/17896441.25d2eecf.js | 1 + docs/0.16.0/assets/js/1798d0b3.36e85a04.js | 1 + docs/0.16.0/assets/js/194e858c.98c96ae7.js | 1 + docs/0.16.0/assets/js/1a3daba8.ac1ba8e8.js | 1 + docs/0.16.0/assets/js/1b8ca8c3.4358a704.js | 1 + docs/0.16.0/assets/js/1be78505.08a4249d.js | 1 + docs/0.16.0/assets/js/1c41eae2.66378d8d.js | 1 + docs/0.16.0/assets/js/1c93e70c.77ab6302.js | 1 + docs/0.16.0/assets/js/1cdac986.f465f273.js | 1 + docs/0.16.0/assets/js/1ce64703.168baa89.js | 1 + docs/0.16.0/assets/js/1e4e1fb6.352993fe.js | 1 + docs/0.16.0/assets/js/20e2ece2.6327fef8.js | 1 + docs/0.16.0/assets/js/2149662b.86af6d60.js | 1 + docs/0.16.0/assets/js/234733fd.413dbe85.js | 1 + docs/0.16.0/assets/js/23f93eeb.c9adc153.js | 1 + docs/0.16.0/assets/js/25196878.ca24ae51.js | 1 + docs/0.16.0/assets/js/26c0a43c.fc23d5e4.js | 1 + docs/0.16.0/assets/js/29fadaa3.5953c4d1.js | 1 + docs/0.16.0/assets/js/2a4d41ed.52ff89d0.js | 1 + docs/0.16.0/assets/js/2b265210.b10c2ab1.js | 1 + docs/0.16.0/assets/js/2bb892db.7dbc4c68.js | 1 + docs/0.16.0/assets/js/2c0d2b92.f8c85258.js | 1 + docs/0.16.0/assets/js/2d9479c4.60ec37b5.js | 1 + docs/0.16.0/assets/js/2f7bd5c8.56754015.js | 1 + docs/0.16.0/assets/js/31526b20.042cabc1.js | 1 + docs/0.16.0/assets/js/3245f64b.3f312bbc.js | 1 + docs/0.16.0/assets/js/345c600d.d35af627.js | 1 + docs/0.16.0/assets/js/376759eb.a26c2de9.js | 1 + docs/0.16.0/assets/js/382b9f11.ecb346c2.js | 1 + docs/0.16.0/assets/js/385623dc.79e6e52e.js | 1 + docs/0.16.0/assets/js/3961e600.447d8182.js | 1 + docs/0.16.0/assets/js/3cfbc8af.042652b0.js | 1 + docs/0.16.0/assets/js/3ee3a370.68b8d0ad.js | 1 + docs/0.16.0/assets/js/402da695.dca958f2.js | 1 + docs/0.16.0/assets/js/41718851.37d8e0c9.js | 1 + docs/0.16.0/assets/js/425cb3cb.214e68a0.js | 1 + docs/0.16.0/assets/js/44954150.17b33b16.js | 1 + docs/0.16.0/assets/js/44f79c8d.0eabe5cf.js | 1 + docs/0.16.0/assets/js/46076c8b.dd37858a.js | 1 + docs/0.16.0/assets/js/463dc00f.a9cd6d15.js | 1 + docs/0.16.0/assets/js/47e70afa.c24efe3f.js | 1 + docs/0.16.0/assets/js/482a391c.b8ab4399.js | 1 + docs/0.16.0/assets/js/488157d7.4b4eebc3.js | 1 + docs/0.16.0/assets/js/4a9d0f4c.65b12999.js | 1 + docs/0.16.0/assets/js/4aa001c0.c8372f9f.js | 1 + docs/0.16.0/assets/js/4add0c6c.7ed8ffdc.js | 1 + docs/0.16.0/assets/js/4be897c9.e7b3c387.js | 1 + docs/0.16.0/assets/js/4d9df5b1.71153059.js | 1 + docs/0.16.0/assets/js/4f675ae9.2aee3ba3.js | 1 + docs/0.16.0/assets/js/5058a078.d2f3c214.js | 1 + docs/0.16.0/assets/js/50818478.556f0b73.js | 1 + docs/0.16.0/assets/js/5242ac2d.16055ebb.js | 1 + docs/0.16.0/assets/js/56ccfc32.2dcbb12d.js | 1 + docs/0.16.0/assets/js/575d1ad6.074a3068.js | 1 + docs/0.16.0/assets/js/5a8c7729.77c8d70b.js | 1 + docs/0.16.0/assets/js/5cdfb1f2.9bdca8fe.js | 1 + docs/0.16.0/assets/js/5df6e7df.487902f2.js | 1 + docs/0.16.0/assets/js/5eabd930.fbc0a29f.js | 1 + docs/0.16.0/assets/js/67d1434e.85b319c4.js | 1 + docs/0.16.0/assets/js/6870612e.6f228bb6.js | 1 + docs/0.16.0/assets/js/6875c492.c67f2e73.js | 1 + docs/0.16.0/assets/js/68c17ba1.56cc7f22.js | 1 + docs/0.16.0/assets/js/6a35a4d8.35bcee7f.js | 1 + docs/0.16.0/assets/js/6ba4a510.b8825408.js | 1 + docs/0.16.0/assets/js/6c5232c2.fafd0f71.js | 1 + docs/0.16.0/assets/js/6d2a6c9a.899740c3.js | 1 + docs/0.16.0/assets/js/6e772156.de8699ba.js | 1 + docs/0.16.0/assets/js/6ff6e7c9.34518733.js | 1 + docs/0.16.0/assets/js/723607d1.e3c765d2.js | 1 + docs/0.16.0/assets/js/72c409f7.37981358.js | 1 + docs/0.16.0/assets/js/7310a4fe.cb7c0f12.js | 1 + docs/0.16.0/assets/js/7457c448.8eae7baa.js | 1 + docs/0.16.0/assets/js/7538b401.9467be0b.js | 1 + docs/0.16.0/assets/js/75880d90.d5ebfb17.js | 1 + docs/0.16.0/assets/js/76bcd116.31f94fcd.js | 1 + docs/0.16.0/assets/js/772fc39d.44e54754.js | 1 + docs/0.16.0/assets/js/77cc432a.d85baedd.js | 1 + docs/0.16.0/assets/js/7d170ab0.638674ff.js | 1 + docs/0.16.0/assets/js/7e0ce508.7eebaf2e.js | 1 + docs/0.16.0/assets/js/7ea7f008.1e86f06b.js | 1 + docs/0.16.0/assets/js/7f479c52.1ff8ee6e.js | 1 + docs/0.16.0/assets/js/814f3328.24525a8b.js | 1 + docs/0.16.0/assets/js/81bf07f5.ce836a1d.js | 1 + docs/0.16.0/assets/js/81f6aa2c.ee049a89.js | 1 + docs/0.16.0/assets/js/8382.3c17fd52.js | 1 + docs/0.16.0/assets/js/83b912d4.ab8880e8.js | 1 + docs/0.16.0/assets/js/8417e7a5.dcd6c648.js | 1 + docs/0.16.0/assets/js/85afcbde.5593c8d3.js | 1 + docs/0.16.0/assets/js/86a1f821.7ee13ee9.js | 1 + docs/0.16.0/assets/js/8809.44c4a575.js | 1 + docs/0.16.0/assets/js/89196f72.edb5fbb7.js | 1 + docs/0.16.0/assets/js/89fc5f00.a011da22.js | 1 + docs/0.16.0/assets/js/8be9dc67.6449ddb1.js | 1 + docs/0.16.0/assets/js/8c7569e5.4214ccc3.js | 1 + docs/0.16.0/assets/js/8cf2dd9c.d59af323.js | 1 + docs/0.16.0/assets/js/8d6e802b.dffe0fdb.js | 1 + docs/0.16.0/assets/js/920bdc78.764abce5.js | 1 + docs/0.16.0/assets/js/928a5d6f.b84c0c0b.js | 1 + docs/0.16.0/assets/js/92dd0956.d500cc47.js | 1 + docs/0.16.0/assets/js/935f2afb.2f263db7.js | 1 + docs/0.16.0/assets/js/952dfacb.b6458afa.js | 1 + docs/0.16.0/assets/js/97081ee7.4d3ce296.js | 1 + docs/0.16.0/assets/js/980f8d5e.0a236b42.js | 1 + docs/0.16.0/assets/js/98184455.9f967dd2.js | 1 + docs/0.16.0/assets/js/98306a23.b1ce97fe.js | 1 + docs/0.16.0/assets/js/9a1c8bc6.dce511c1.js | 1 + docs/0.16.0/assets/js/9a3e57da.6cf35ab2.js | 1 + docs/0.16.0/assets/js/9c5158ac.353fe2b2.js | 1 + docs/0.16.0/assets/js/9c7b888e.0f19b601.js | 1 + docs/0.16.0/assets/js/9e4087bc.fd7711ba.js | 1 + docs/0.16.0/assets/js/9edb318c.9950535d.js | 1 + docs/0.16.0/assets/js/a2ab2bad.24b45834.js | 1 + docs/0.16.0/assets/js/a470b55c.c5b0f903.js | 1 + docs/0.16.0/assets/js/a4bc1622.56c7a466.js | 1 + docs/0.16.0/assets/js/a5971d1a.0ab74105.js | 1 + docs/0.16.0/assets/js/a6aa9e1f.c5d6d672.js | 1 + docs/0.16.0/assets/js/a6b6486c.7066e9bb.js | 1 + docs/0.16.0/assets/js/a7153b78.a2b5a6f6.js | 1 + docs/0.16.0/assets/js/a7e6874c.32075221.js | 1 + docs/0.16.0/assets/js/a87d47f1.638107c7.js | 1 + docs/0.16.0/assets/js/a8d11699.0e5d0034.js | 1 + docs/0.16.0/assets/js/a9e26133.7429af4a.js | 1 + docs/0.16.0/assets/js/aa1cf9a2.52828c0e.js | 1 + docs/0.16.0/assets/js/acfabe81.2547b40d.js | 1 + docs/0.16.0/assets/js/ae3eef3e.eb463894.js | 1 + docs/0.16.0/assets/js/ae967838.0bc2b7aa.js | 1 + docs/0.16.0/assets/js/afebe5f1.5fe2a23f.js | 1 + docs/0.16.0/assets/js/aff456d7.8f09df74.js | 1 + docs/0.16.0/assets/js/b209ab8a.cf366253.js | 1 + docs/0.16.0/assets/js/b3de9677.5c877865.js | 1 + docs/0.16.0/assets/js/b57ca7d5.032ee46f.js | 1 + docs/0.16.0/assets/js/b6bceaff.19fa54f6.js | 1 + docs/0.16.0/assets/js/b7661aba.2998c510.js | 1 + docs/0.16.0/assets/js/b7da1136.344a5231.js | 1 + docs/0.16.0/assets/js/ba43b2d5.5ca14789.js | 1 + docs/0.16.0/assets/js/bac2c42d.f5a5b87a.js | 1 + docs/0.16.0/assets/js/bb43b8ce.0fddfec9.js | 1 + docs/0.16.0/assets/js/bfb64759.8ed694c2.js | 1 + docs/0.16.0/assets/js/c251e734.3fd3d58f.js | 1 + docs/0.16.0/assets/js/c2e5ab4f.ab7e6240.js | 1 + docs/0.16.0/assets/js/c30ee527.527297e3.js | 1 + docs/0.16.0/assets/js/c34cc4c9.56ce985b.js | 1 + docs/0.16.0/assets/js/c377a04b.809da12b.js | 1 + docs/0.16.0/assets/js/c3b79ba0.05e34179.js | 1 + docs/0.16.0/assets/js/c5b25a7c.95edb7f7.js | 1 + docs/0.16.0/assets/js/c5c08033.3258f7d1.js | 1 + docs/0.16.0/assets/js/c5e834bc.7eb47f50.js | 1 + docs/0.16.0/assets/js/c97e0540.375c7725.js | 1 + docs/0.16.0/assets/js/c9d1eb08.85ddc867.js | 1 + docs/0.16.0/assets/js/ca8fbf24.d1ac6d6a.js | 1 + docs/0.16.0/assets/js/cba69ead.8298012c.js | 1 + docs/0.16.0/assets/js/ccc49370.db557050.js | 1 + docs/0.16.0/assets/js/cdaafcc9.085c239c.js | 1 + docs/0.16.0/assets/js/cf518063.ebb43726.js | 1 + docs/0.16.0/assets/js/d077f377.2c3c9edc.js | 1 + docs/0.16.0/assets/js/d0ba620f.f8ae8564.js | 1 + docs/0.16.0/assets/js/d4251823.1b779bc7.js | 1 + docs/0.16.0/assets/js/d5aa49f9.6dad4890.js | 1 + docs/0.16.0/assets/js/d7a493e6.f2613a57.js | 1 + docs/0.16.0/assets/js/d8746e52.e4d0dc41.js | 1 + docs/0.16.0/assets/js/d941076d.e217ef5e.js | 1 + docs/0.16.0/assets/js/d97b7d4d.9b38cbbf.js | 1 + docs/0.16.0/assets/js/dafe2799.0365f5ae.js | 1 + docs/0.16.0/assets/js/db0d9cb2.c1e2f54b.js | 1 + docs/0.16.0/assets/js/dc8f2f6c.1fb3dce7.js | 1 + docs/0.16.0/assets/js/dd9db7c1.95fe8d2d.js | 1 + docs/0.16.0/assets/js/df2eb7da.6039d156.js | 1 + docs/0.16.0/assets/js/e06425d1.7677941c.js | 1 + docs/0.16.0/assets/js/e10f7c24.1537803d.js | 1 + docs/0.16.0/assets/js/e158c27a.75d2740d.js | 1 + docs/0.16.0/assets/js/e329d2fa.594a299b.js | 1 + docs/0.16.0/assets/js/e46b95eb.b729c545.js | 1 + docs/0.16.0/assets/js/e4f709d1.622e5fc6.js | 1 + docs/0.16.0/assets/js/e5f53749.cd665626.js | 1 + docs/0.16.0/assets/js/e68f8ad6.c1a8db19.js | 1 + docs/0.16.0/assets/js/ebe12d94.e9202909.js | 1 + docs/0.16.0/assets/js/ec040517.f0e83778.js | 1 + docs/0.16.0/assets/js/ec49082b.0c5dd593.js | 1 + docs/0.16.0/assets/js/eceb3b9b.bc074cbb.js | 1 + docs/0.16.0/assets/js/edb9b0b8.52075b0f.js | 1 + docs/0.16.0/assets/js/ee244d12.81f504bd.js | 1 + docs/0.16.0/assets/js/f11e9837.fbbfe220.js | 1 + docs/0.16.0/assets/js/f1257df2.c27413b8.js | 1 + docs/0.16.0/assets/js/f18bbaf6.3a12296c.js | 1 + docs/0.16.0/assets/js/f33f2c05.bece9048.js | 1 + docs/0.16.0/assets/js/f6ca3de5.1be337f5.js | 1 + docs/0.16.0/assets/js/f7912ff8.139c630a.js | 1 + docs/0.16.0/assets/js/f87e687e.8a0ae88d.js | 1 + docs/0.16.0/assets/js/f914cfe8.0c3fe5c5.js | 1 + docs/0.16.0/assets/js/f9553497.6168470e.js | 1 + docs/0.16.0/assets/js/fa5466f2.c7b13c43.js | 1 + docs/0.16.0/assets/js/faca410e.0cb58136.js | 1 + docs/0.16.0/assets/js/ff7b8d8e.2839820c.js | 1 + docs/0.16.0/assets/js/main.d2f0168d.js | 2 + .../assets/js/main.d2f0168d.js.LICENSE.txt | 63 +++++++ .../0.16.0/assets/js/runtime~main.0eac1086.js | 1 + .../expressions/conditional/index.html | 17 ++ .../ast-builder/expressions/nested/index.html | 17 ++ .../expressions/operator-based/index.html | 17 ++ .../expressions/pattern-matching/index.html | 17 ++ .../expressions/value-checking/index.html | 17 ++ .../date-&-time/conversion/index.html | 17 ++ .../current-date-and-time/index.html | 17 ++ .../date-and-time-extraction/index.html | 17 ++ .../date-&-time/formatting/index.html | 17 ++ .../geometry/coordinate-extraction/index.html | 17 ++ .../geometry/distance-calculation/index.html | 17 ++ .../geometry/point-creation/index.html | 17 ++ .../list-and-map-concatenation/index.html | 17 ++ .../list-&-map/list-manipulation/index.html | 17 ++ .../math/basic-arithmetic/index.html | 17 ++ .../functions/math/conversion/index.html | 17 ++ .../logarithmic-and-exponential/index.html | 17 ++ .../functions/math/rounding/index.html | 17 ++ .../math/special-mathematical/index.html | 17 ++ .../functions/math/trigonometric/index.html | 17 ++ .../functions/others/null-handling/index.html | 17 ++ .../others/type-conversion/index.html | 17 ++ .../others/unique-identifier/index.html | 17 ++ .../functions/text/case-conversion/index.html | 17 ++ .../text/character-conversion/index.html | 17 ++ .../functions/text/padding/index.html | 17 ++ .../text/position-and-indexing/index.html | 17 ++ .../text/text-manipulation/index.html | 17 ++ .../functions/text/trimming/index.html | 17 ++ docs/0.16.0/ast-builder/intro/index.html | 17 ++ .../deleting-data/index.html | 17 ++ .../inserting-data/index.html | 17 ++ .../updating-data/index.html | 17 ++ .../creating-derived-subqueries/index.html | 17 ++ .../querying/data-aggregation/index.html | 17 ++ .../querying/data-injection/index.html | 17 ++ .../querying/data-joining/index.html | 17 ++ .../data-selection-and-projection/index.html | 17 ++ .../data-sorting-and-limiting/index.html | 17 ++ .../fetching-data-from-storage/index.html | 17 ++ .../querying/using-preloaded-data/index.html | 17 ++ docs/0.16.0/blog/archive/index.html | 17 ++ docs/0.16.0/blog/atom.xml | 102 +++++++++++ .../index.html | 29 +++ docs/0.16.0/blog/index.html | 32 ++++ docs/0.16.0/blog/release-v0.14/index.html | 19 ++ docs/0.16.0/blog/release-v0.15/index.html | 17 ++ .../index.html | 18 ++ docs/0.16.0/blog/rss.xml | 84 +++++++++ docs/0.16.0/blog/tags/automation/index.html | 17 ++ docs/0.16.0/blog/tags/chat-gpt/index.html | 17 ++ docs/0.16.0/blog/tags/database/index.html | 30 +++ .../0.16.0/blog/tags/documentation/index.html | 17 ++ docs/0.16.0/blog/tags/gluesql/index.html | 18 ++ docs/0.16.0/blog/tags/index.html | 17 ++ docs/0.16.0/blog/tags/nosql/index.html | 29 +++ docs/0.16.0/blog/tags/proposal/index.html | 18 ++ .../blog/tags/query-interface/index.html | 18 ++ docs/0.16.0/blog/tags/release-note/index.html | 19 ++ docs/0.16.0/blog/tags/sql/index.html | 29 +++ docs/0.16.0/blog/tags/tdd/index.html | 17 ++ .../tags/test-driven-documentation/index.html | 17 ++ docs/0.16.0/blog/tags/v-0-14/index.html | 19 ++ docs/0.16.0/blog/tags/v-0-15/index.html | 17 ++ .../blog/test-driven-documentation/index.html | 17 ++ docs/0.16.0/getting-started/cli/index.html | 17 ++ .../getting-started/javascript-web/index.html | 17 ++ docs/0.16.0/getting-started/nodejs/index.html | 17 ++ docs/0.16.0/getting-started/rust/index.html | 17 ++ docs/0.16.0/img/favicon.ico | Bin 0 -> 15406 bytes docs/0.16.0/img/gluesql.jpg | Bin 0 -> 98306 bytes .../0.16.0/img/undraw_docusaurus_mountain.svg | 171 ++++++++++++++++++ docs/0.16.0/img/undraw_docusaurus_react.svg | 170 +++++++++++++++++ docs/0.16.0/img/undraw_docusaurus_tree.svg | 40 ++++ docs/0.16.0/index.html | 25 +++ docs/0.16.0/sitemap.xml | 1 + .../sql-syntax/data-types/boolean/index.html | 17 ++ .../sql-syntax/data-types/bytea/index.html | 17 ++ .../sql-syntax/data-types/date/index.html | 17 ++ .../sql-syntax/data-types/decimal/index.html | 17 ++ .../sql-syntax/data-types/float/index.html | 17 ++ .../sql-syntax/data-types/inet/index.html | 17 ++ .../sql-syntax/data-types/integers/index.html | 17 ++ .../sql-syntax/data-types/interval/index.html | 17 ++ .../sql-syntax/data-types/list/index.html | 17 ++ .../sql-syntax/data-types/map/index.html | 17 ++ .../sql-syntax/data-types/text/index.html | 17 ++ .../sql-syntax/data-types/time/index.html | 17 ++ .../data-types/timestamp/index.html | 17 ++ .../sql-syntax/data-types/uuid/index.html | 17 ++ .../functions/datetime/extract/index.html | 17 ++ .../functions/datetime/format/index.html | 17 ++ .../functions/datetime/now/index.html | 17 ++ .../functions/datetime/to-date/index.html | 17 ++ .../functions/datetime/to-time/index.html | 17 ++ .../datetime/to-timestamp/index.html | 17 ++ .../geometry/calc-distance/index.html | 17 ++ .../functions/geometry/get-x/index.html | 17 ++ .../functions/geometry/get-y/index.html | 17 ++ .../functions/geometry/point/index.html | 17 ++ .../functions/list-map/append/index.html | 17 ++ .../functions/list-map/concat/index.html | 17 ++ .../functions/list-map/prepend/index.html | 17 ++ .../functions/list-map/slice/index.html | 17 ++ .../functions/list-map/splice/index.html | 17 ++ .../sql-syntax/functions/math/abs/index.html | 17 ++ .../sql-syntax/functions/math/acos/index.html | 17 ++ .../sql-syntax/functions/math/asin/index.html | 17 ++ .../sql-syntax/functions/math/atan/index.html | 17 ++ .../sql-syntax/functions/math/ceil/index.html | 17 ++ .../sql-syntax/functions/math/cos/index.html | 17 ++ .../functions/math/degrees/index.html | 17 ++ .../sql-syntax/functions/math/div/index.html | 17 ++ .../sql-syntax/functions/math/exp/index.html | 17 ++ .../functions/math/floor/index.html | 17 ++ .../sql-syntax/functions/math/gcd/index.html | 17 ++ .../sql-syntax/functions/math/lcm/index.html | 17 ++ .../sql-syntax/functions/math/ln/index.html | 17 ++ .../sql-syntax/functions/math/log/index.html | 17 ++ .../functions/math/log10/index.html | 17 ++ .../sql-syntax/functions/math/log2/index.html | 17 ++ .../sql-syntax/functions/math/mod/index.html | 17 ++ .../sql-syntax/functions/math/pi/index.html | 17 ++ .../functions/math/power/index.html | 17 ++ .../functions/math/radians/index.html | 17 ++ .../sql-syntax/functions/math/rand/index.html | 17 ++ .../functions/math/round/index.html | 17 ++ .../sql-syntax/functions/math/sign/index.html | 17 ++ .../sql-syntax/functions/math/sin/index.html | 17 ++ .../sql-syntax/functions/math/sqrt/index.html | 17 ++ .../sql-syntax/functions/math/tan/index.html | 17 ++ .../functions/others/cast/index.html | 17 ++ .../functions/others/generate-uuid/index.html | 17 ++ .../functions/others/ifnull/index.html | 17 ++ .../functions/text/ascii/index.html | 17 ++ .../sql-syntax/functions/text/chr/index.html | 17 ++ .../functions/text/concat-ws/index.html | 17 ++ .../functions/text/concat/index.html | 17 ++ .../functions/text/find-idx/index.html | 17 ++ .../functions/text/initcap/index.html | 17 ++ .../sql-syntax/functions/text/left/index.html | 17 ++ .../functions/text/lower/index.html | 17 ++ .../sql-syntax/functions/text/lpad/index.html | 17 ++ .../functions/text/ltrim/index.html | 17 ++ .../functions/text/position/index.html | 17 ++ .../functions/text/repeat/index.html | 17 ++ .../functions/text/reverse/index.html | 17 ++ .../functions/text/right/index.html | 17 ++ .../sql-syntax/functions/text/rpad/index.html | 17 ++ .../functions/text/rtrim/index.html | 17 ++ .../functions/text/substr/index.html | 17 ++ .../sql-syntax/functions/text/trim/index.html | 17 ++ .../functions/text/upper/index.html | 17 ++ docs/0.16.0/sql-syntax/intro/index.html | 18 ++ .../data-definition/alter-table/index.html | 17 ++ .../data-definition/create-index/index.html | 17 ++ .../data-definition/create-table/index.html | 17 ++ .../data-definition/drop-index/index.html | 17 ++ .../data-definition/drop-table/index.html | 17 ++ .../data-manipulation/delete/index.html | 17 ++ .../data-manipulation/insert/index.html | 17 ++ .../data-manipulation/update/index.html | 17 ++ .../metadata/data-dictionary/index.html | 17 ++ .../metadata/show-tables/index.html | 17 ++ .../querying/aggregation/index.html | 17 ++ .../statements/querying/join/index.html | 17 ++ .../statements/querying/limit/index.html | 17 ++ .../statements/querying/schemaless/index.html | 17 ++ .../statements/querying/where/index.html | 17 ++ .../statements/transaction/index.html | 17 ++ .../intro/index.html | 17 ++ .../store-traits/alter-table/index.html | 17 ++ .../custom-function-mut/index.html | 17 ++ .../store-traits/custom-function/index.html | 17 ++ .../store-traits/index-mut/index.html | 17 ++ .../store-traits/index-trait/index.html | 17 ++ .../store-traits/metadata/index.html | 17 ++ .../store-traits/store-mut/index.html | 17 ++ .../store-traits/store/index.html | 17 ++ .../store-traits/transaction/index.html | 17 ++ .../using-test-suite/index.html | 17 ++ docs/0.16.0/storages/intro/index.html | 17 ++ .../composite-storage/index.html | 17 ++ .../supported-storages/csv-storage/index.html | 17 ++ .../supported-storages/idb-storage/index.html | 17 ++ .../json-storage/index.html | 19 ++ .../memory-storage/index.html | 17 ++ .../parquet-storage/index.html | 21 +++ .../shared-memory-storage/index.html | 17 ++ .../sled-storage/index.html | 17 ++ .../supported-storages/web-storage/index.html | 17 ++ 415 files changed, 4068 insertions(+) create mode 100644 docs/0.16.0/.nojekyll create mode 100644 docs/0.16.0/404.html create mode 100644 docs/0.16.0/assets/css/styles.1b097026.css create mode 100644 docs/0.16.0/assets/images/blog-test-driven-documentation-insert-7dfbb3a9123d4aa47b845b7dede97dc9.jpg create mode 100644 docs/0.16.0/assets/images/blog-test-driven-documentation-insert-errorcase-1be5ced205cee0d2eeb56af1591440ac.jpg create mode 100644 docs/0.16.0/assets/js/007e0817.64d185e0.js create mode 100644 docs/0.16.0/assets/js/017e736e.f5dc6055.js create mode 100644 docs/0.16.0/assets/js/01a12966.469b19f8.js create mode 100644 docs/0.16.0/assets/js/01a85c17.de44d5e4.js create mode 100644 docs/0.16.0/assets/js/02aa4531.17b335fe.js create mode 100644 docs/0.16.0/assets/js/02bfc02d.c93d2576.js create mode 100644 docs/0.16.0/assets/js/037683de.b9938f31.js create mode 100644 docs/0.16.0/assets/js/045be9fd.bc59c80a.js create mode 100644 docs/0.16.0/assets/js/0544f90b.ccc9e299.js create mode 100644 docs/0.16.0/assets/js/06322d53.4d22d233.js create mode 100644 docs/0.16.0/assets/js/07294b24.663c5d97.js create mode 100644 docs/0.16.0/assets/js/078a6308.4d53bdee.js create mode 100644 docs/0.16.0/assets/js/0b621d16.b92732eb.js create mode 100644 docs/0.16.0/assets/js/0c18287f.2d4dde49.js create mode 100644 docs/0.16.0/assets/js/0c94c658.a5f781c3.js create mode 100644 docs/0.16.0/assets/js/0ea64360.3dae4181.js create mode 100644 docs/0.16.0/assets/js/104749c9.09fc621f.js create mode 100644 docs/0.16.0/assets/js/107910e9.5dfe754c.js create mode 100644 docs/0.16.0/assets/js/15868c40.654d0d37.js create mode 100644 docs/0.16.0/assets/js/160faf1d.05a9000e.js create mode 100644 docs/0.16.0/assets/js/16682cd3.e744db6a.js create mode 100644 docs/0.16.0/assets/js/16815c2a.9ebfe213.js create mode 100644 docs/0.16.0/assets/js/1774.e76e375b.js create mode 100644 docs/0.16.0/assets/js/17896441.25d2eecf.js create mode 100644 docs/0.16.0/assets/js/1798d0b3.36e85a04.js create mode 100644 docs/0.16.0/assets/js/194e858c.98c96ae7.js create mode 100644 docs/0.16.0/assets/js/1a3daba8.ac1ba8e8.js create mode 100644 docs/0.16.0/assets/js/1b8ca8c3.4358a704.js create mode 100644 docs/0.16.0/assets/js/1be78505.08a4249d.js create mode 100644 docs/0.16.0/assets/js/1c41eae2.66378d8d.js create mode 100644 docs/0.16.0/assets/js/1c93e70c.77ab6302.js create mode 100644 docs/0.16.0/assets/js/1cdac986.f465f273.js create mode 100644 docs/0.16.0/assets/js/1ce64703.168baa89.js create mode 100644 docs/0.16.0/assets/js/1e4e1fb6.352993fe.js create mode 100644 docs/0.16.0/assets/js/20e2ece2.6327fef8.js create mode 100644 docs/0.16.0/assets/js/2149662b.86af6d60.js create mode 100644 docs/0.16.0/assets/js/234733fd.413dbe85.js create mode 100644 docs/0.16.0/assets/js/23f93eeb.c9adc153.js create mode 100644 docs/0.16.0/assets/js/25196878.ca24ae51.js create mode 100644 docs/0.16.0/assets/js/26c0a43c.fc23d5e4.js create mode 100644 docs/0.16.0/assets/js/29fadaa3.5953c4d1.js create mode 100644 docs/0.16.0/assets/js/2a4d41ed.52ff89d0.js create mode 100644 docs/0.16.0/assets/js/2b265210.b10c2ab1.js create mode 100644 docs/0.16.0/assets/js/2bb892db.7dbc4c68.js create mode 100644 docs/0.16.0/assets/js/2c0d2b92.f8c85258.js create mode 100644 docs/0.16.0/assets/js/2d9479c4.60ec37b5.js create mode 100644 docs/0.16.0/assets/js/2f7bd5c8.56754015.js create mode 100644 docs/0.16.0/assets/js/31526b20.042cabc1.js create mode 100644 docs/0.16.0/assets/js/3245f64b.3f312bbc.js create mode 100644 docs/0.16.0/assets/js/345c600d.d35af627.js create mode 100644 docs/0.16.0/assets/js/376759eb.a26c2de9.js create mode 100644 docs/0.16.0/assets/js/382b9f11.ecb346c2.js create mode 100644 docs/0.16.0/assets/js/385623dc.79e6e52e.js create mode 100644 docs/0.16.0/assets/js/3961e600.447d8182.js create mode 100644 docs/0.16.0/assets/js/3cfbc8af.042652b0.js create mode 100644 docs/0.16.0/assets/js/3ee3a370.68b8d0ad.js create mode 100644 docs/0.16.0/assets/js/402da695.dca958f2.js create mode 100644 docs/0.16.0/assets/js/41718851.37d8e0c9.js create mode 100644 docs/0.16.0/assets/js/425cb3cb.214e68a0.js create mode 100644 docs/0.16.0/assets/js/44954150.17b33b16.js create mode 100644 docs/0.16.0/assets/js/44f79c8d.0eabe5cf.js create mode 100644 docs/0.16.0/assets/js/46076c8b.dd37858a.js create mode 100644 docs/0.16.0/assets/js/463dc00f.a9cd6d15.js create mode 100644 docs/0.16.0/assets/js/47e70afa.c24efe3f.js create mode 100644 docs/0.16.0/assets/js/482a391c.b8ab4399.js create mode 100644 docs/0.16.0/assets/js/488157d7.4b4eebc3.js create mode 100644 docs/0.16.0/assets/js/4a9d0f4c.65b12999.js create mode 100644 docs/0.16.0/assets/js/4aa001c0.c8372f9f.js create mode 100644 docs/0.16.0/assets/js/4add0c6c.7ed8ffdc.js create mode 100644 docs/0.16.0/assets/js/4be897c9.e7b3c387.js create mode 100644 docs/0.16.0/assets/js/4d9df5b1.71153059.js create mode 100644 docs/0.16.0/assets/js/4f675ae9.2aee3ba3.js create mode 100644 docs/0.16.0/assets/js/5058a078.d2f3c214.js create mode 100644 docs/0.16.0/assets/js/50818478.556f0b73.js create mode 100644 docs/0.16.0/assets/js/5242ac2d.16055ebb.js create mode 100644 docs/0.16.0/assets/js/56ccfc32.2dcbb12d.js create mode 100644 docs/0.16.0/assets/js/575d1ad6.074a3068.js create mode 100644 docs/0.16.0/assets/js/5a8c7729.77c8d70b.js create mode 100644 docs/0.16.0/assets/js/5cdfb1f2.9bdca8fe.js create mode 100644 docs/0.16.0/assets/js/5df6e7df.487902f2.js create mode 100644 docs/0.16.0/assets/js/5eabd930.fbc0a29f.js create mode 100644 docs/0.16.0/assets/js/67d1434e.85b319c4.js create mode 100644 docs/0.16.0/assets/js/6870612e.6f228bb6.js create mode 100644 docs/0.16.0/assets/js/6875c492.c67f2e73.js create mode 100644 docs/0.16.0/assets/js/68c17ba1.56cc7f22.js create mode 100644 docs/0.16.0/assets/js/6a35a4d8.35bcee7f.js create mode 100644 docs/0.16.0/assets/js/6ba4a510.b8825408.js create mode 100644 docs/0.16.0/assets/js/6c5232c2.fafd0f71.js create mode 100644 docs/0.16.0/assets/js/6d2a6c9a.899740c3.js create mode 100644 docs/0.16.0/assets/js/6e772156.de8699ba.js create mode 100644 docs/0.16.0/assets/js/6ff6e7c9.34518733.js create mode 100644 docs/0.16.0/assets/js/723607d1.e3c765d2.js create mode 100644 docs/0.16.0/assets/js/72c409f7.37981358.js create mode 100644 docs/0.16.0/assets/js/7310a4fe.cb7c0f12.js create mode 100644 docs/0.16.0/assets/js/7457c448.8eae7baa.js create mode 100644 docs/0.16.0/assets/js/7538b401.9467be0b.js create mode 100644 docs/0.16.0/assets/js/75880d90.d5ebfb17.js create mode 100644 docs/0.16.0/assets/js/76bcd116.31f94fcd.js create mode 100644 docs/0.16.0/assets/js/772fc39d.44e54754.js create mode 100644 docs/0.16.0/assets/js/77cc432a.d85baedd.js create mode 100644 docs/0.16.0/assets/js/7d170ab0.638674ff.js create mode 100644 docs/0.16.0/assets/js/7e0ce508.7eebaf2e.js create mode 100644 docs/0.16.0/assets/js/7ea7f008.1e86f06b.js create mode 100644 docs/0.16.0/assets/js/7f479c52.1ff8ee6e.js create mode 100644 docs/0.16.0/assets/js/814f3328.24525a8b.js create mode 100644 docs/0.16.0/assets/js/81bf07f5.ce836a1d.js create mode 100644 docs/0.16.0/assets/js/81f6aa2c.ee049a89.js create mode 100644 docs/0.16.0/assets/js/8382.3c17fd52.js create mode 100644 docs/0.16.0/assets/js/83b912d4.ab8880e8.js create mode 100644 docs/0.16.0/assets/js/8417e7a5.dcd6c648.js create mode 100644 docs/0.16.0/assets/js/85afcbde.5593c8d3.js create mode 100644 docs/0.16.0/assets/js/86a1f821.7ee13ee9.js create mode 100644 docs/0.16.0/assets/js/8809.44c4a575.js create mode 100644 docs/0.16.0/assets/js/89196f72.edb5fbb7.js create mode 100644 docs/0.16.0/assets/js/89fc5f00.a011da22.js create mode 100644 docs/0.16.0/assets/js/8be9dc67.6449ddb1.js create mode 100644 docs/0.16.0/assets/js/8c7569e5.4214ccc3.js create mode 100644 docs/0.16.0/assets/js/8cf2dd9c.d59af323.js create mode 100644 docs/0.16.0/assets/js/8d6e802b.dffe0fdb.js create mode 100644 docs/0.16.0/assets/js/920bdc78.764abce5.js create mode 100644 docs/0.16.0/assets/js/928a5d6f.b84c0c0b.js create mode 100644 docs/0.16.0/assets/js/92dd0956.d500cc47.js create mode 100644 docs/0.16.0/assets/js/935f2afb.2f263db7.js create mode 100644 docs/0.16.0/assets/js/952dfacb.b6458afa.js create mode 100644 docs/0.16.0/assets/js/97081ee7.4d3ce296.js create mode 100644 docs/0.16.0/assets/js/980f8d5e.0a236b42.js create mode 100644 docs/0.16.0/assets/js/98184455.9f967dd2.js create mode 100644 docs/0.16.0/assets/js/98306a23.b1ce97fe.js create mode 100644 docs/0.16.0/assets/js/9a1c8bc6.dce511c1.js create mode 100644 docs/0.16.0/assets/js/9a3e57da.6cf35ab2.js create mode 100644 docs/0.16.0/assets/js/9c5158ac.353fe2b2.js create mode 100644 docs/0.16.0/assets/js/9c7b888e.0f19b601.js create mode 100644 docs/0.16.0/assets/js/9e4087bc.fd7711ba.js create mode 100644 docs/0.16.0/assets/js/9edb318c.9950535d.js create mode 100644 docs/0.16.0/assets/js/a2ab2bad.24b45834.js create mode 100644 docs/0.16.0/assets/js/a470b55c.c5b0f903.js create mode 100644 docs/0.16.0/assets/js/a4bc1622.56c7a466.js create mode 100644 docs/0.16.0/assets/js/a5971d1a.0ab74105.js create mode 100644 docs/0.16.0/assets/js/a6aa9e1f.c5d6d672.js create mode 100644 docs/0.16.0/assets/js/a6b6486c.7066e9bb.js create mode 100644 docs/0.16.0/assets/js/a7153b78.a2b5a6f6.js create mode 100644 docs/0.16.0/assets/js/a7e6874c.32075221.js create mode 100644 docs/0.16.0/assets/js/a87d47f1.638107c7.js create mode 100644 docs/0.16.0/assets/js/a8d11699.0e5d0034.js create mode 100644 docs/0.16.0/assets/js/a9e26133.7429af4a.js create mode 100644 docs/0.16.0/assets/js/aa1cf9a2.52828c0e.js create mode 100644 docs/0.16.0/assets/js/acfabe81.2547b40d.js create mode 100644 docs/0.16.0/assets/js/ae3eef3e.eb463894.js create mode 100644 docs/0.16.0/assets/js/ae967838.0bc2b7aa.js create mode 100644 docs/0.16.0/assets/js/afebe5f1.5fe2a23f.js create mode 100644 docs/0.16.0/assets/js/aff456d7.8f09df74.js create mode 100644 docs/0.16.0/assets/js/b209ab8a.cf366253.js create mode 100644 docs/0.16.0/assets/js/b3de9677.5c877865.js create mode 100644 docs/0.16.0/assets/js/b57ca7d5.032ee46f.js create mode 100644 docs/0.16.0/assets/js/b6bceaff.19fa54f6.js create mode 100644 docs/0.16.0/assets/js/b7661aba.2998c510.js create mode 100644 docs/0.16.0/assets/js/b7da1136.344a5231.js create mode 100644 docs/0.16.0/assets/js/ba43b2d5.5ca14789.js create mode 100644 docs/0.16.0/assets/js/bac2c42d.f5a5b87a.js create mode 100644 docs/0.16.0/assets/js/bb43b8ce.0fddfec9.js create mode 100644 docs/0.16.0/assets/js/bfb64759.8ed694c2.js create mode 100644 docs/0.16.0/assets/js/c251e734.3fd3d58f.js create mode 100644 docs/0.16.0/assets/js/c2e5ab4f.ab7e6240.js create mode 100644 docs/0.16.0/assets/js/c30ee527.527297e3.js create mode 100644 docs/0.16.0/assets/js/c34cc4c9.56ce985b.js create mode 100644 docs/0.16.0/assets/js/c377a04b.809da12b.js create mode 100644 docs/0.16.0/assets/js/c3b79ba0.05e34179.js create mode 100644 docs/0.16.0/assets/js/c5b25a7c.95edb7f7.js create mode 100644 docs/0.16.0/assets/js/c5c08033.3258f7d1.js create mode 100644 docs/0.16.0/assets/js/c5e834bc.7eb47f50.js create mode 100644 docs/0.16.0/assets/js/c97e0540.375c7725.js create mode 100644 docs/0.16.0/assets/js/c9d1eb08.85ddc867.js create mode 100644 docs/0.16.0/assets/js/ca8fbf24.d1ac6d6a.js create mode 100644 docs/0.16.0/assets/js/cba69ead.8298012c.js create mode 100644 docs/0.16.0/assets/js/ccc49370.db557050.js create mode 100644 docs/0.16.0/assets/js/cdaafcc9.085c239c.js create mode 100644 docs/0.16.0/assets/js/cf518063.ebb43726.js create mode 100644 docs/0.16.0/assets/js/d077f377.2c3c9edc.js create mode 100644 docs/0.16.0/assets/js/d0ba620f.f8ae8564.js create mode 100644 docs/0.16.0/assets/js/d4251823.1b779bc7.js create mode 100644 docs/0.16.0/assets/js/d5aa49f9.6dad4890.js create mode 100644 docs/0.16.0/assets/js/d7a493e6.f2613a57.js create mode 100644 docs/0.16.0/assets/js/d8746e52.e4d0dc41.js create mode 100644 docs/0.16.0/assets/js/d941076d.e217ef5e.js create mode 100644 docs/0.16.0/assets/js/d97b7d4d.9b38cbbf.js create mode 100644 docs/0.16.0/assets/js/dafe2799.0365f5ae.js create mode 100644 docs/0.16.0/assets/js/db0d9cb2.c1e2f54b.js create mode 100644 docs/0.16.0/assets/js/dc8f2f6c.1fb3dce7.js create mode 100644 docs/0.16.0/assets/js/dd9db7c1.95fe8d2d.js create mode 100644 docs/0.16.0/assets/js/df2eb7da.6039d156.js create mode 100644 docs/0.16.0/assets/js/e06425d1.7677941c.js create mode 100644 docs/0.16.0/assets/js/e10f7c24.1537803d.js create mode 100644 docs/0.16.0/assets/js/e158c27a.75d2740d.js create mode 100644 docs/0.16.0/assets/js/e329d2fa.594a299b.js create mode 100644 docs/0.16.0/assets/js/e46b95eb.b729c545.js create mode 100644 docs/0.16.0/assets/js/e4f709d1.622e5fc6.js create mode 100644 docs/0.16.0/assets/js/e5f53749.cd665626.js create mode 100644 docs/0.16.0/assets/js/e68f8ad6.c1a8db19.js create mode 100644 docs/0.16.0/assets/js/ebe12d94.e9202909.js create mode 100644 docs/0.16.0/assets/js/ec040517.f0e83778.js create mode 100644 docs/0.16.0/assets/js/ec49082b.0c5dd593.js create mode 100644 docs/0.16.0/assets/js/eceb3b9b.bc074cbb.js create mode 100644 docs/0.16.0/assets/js/edb9b0b8.52075b0f.js create mode 100644 docs/0.16.0/assets/js/ee244d12.81f504bd.js create mode 100644 docs/0.16.0/assets/js/f11e9837.fbbfe220.js create mode 100644 docs/0.16.0/assets/js/f1257df2.c27413b8.js create mode 100644 docs/0.16.0/assets/js/f18bbaf6.3a12296c.js create mode 100644 docs/0.16.0/assets/js/f33f2c05.bece9048.js create mode 100644 docs/0.16.0/assets/js/f6ca3de5.1be337f5.js create mode 100644 docs/0.16.0/assets/js/f7912ff8.139c630a.js create mode 100644 docs/0.16.0/assets/js/f87e687e.8a0ae88d.js create mode 100644 docs/0.16.0/assets/js/f914cfe8.0c3fe5c5.js create mode 100644 docs/0.16.0/assets/js/f9553497.6168470e.js create mode 100644 docs/0.16.0/assets/js/fa5466f2.c7b13c43.js create mode 100644 docs/0.16.0/assets/js/faca410e.0cb58136.js create mode 100644 docs/0.16.0/assets/js/ff7b8d8e.2839820c.js create mode 100644 docs/0.16.0/assets/js/main.d2f0168d.js create mode 100644 docs/0.16.0/assets/js/main.d2f0168d.js.LICENSE.txt create mode 100644 docs/0.16.0/assets/js/runtime~main.0eac1086.js create mode 100644 docs/0.16.0/ast-builder/expressions/conditional/index.html create mode 100644 docs/0.16.0/ast-builder/expressions/nested/index.html create mode 100644 docs/0.16.0/ast-builder/expressions/operator-based/index.html create mode 100644 docs/0.16.0/ast-builder/expressions/pattern-matching/index.html create mode 100644 docs/0.16.0/ast-builder/expressions/value-checking/index.html create mode 100644 docs/0.16.0/ast-builder/functions/date-&-time/conversion/index.html create mode 100644 docs/0.16.0/ast-builder/functions/date-&-time/current-date-and-time/index.html create mode 100644 docs/0.16.0/ast-builder/functions/date-&-time/date-and-time-extraction/index.html create mode 100644 docs/0.16.0/ast-builder/functions/date-&-time/formatting/index.html create mode 100644 docs/0.16.0/ast-builder/functions/geometry/coordinate-extraction/index.html create mode 100644 docs/0.16.0/ast-builder/functions/geometry/distance-calculation/index.html create mode 100644 docs/0.16.0/ast-builder/functions/geometry/point-creation/index.html create mode 100644 docs/0.16.0/ast-builder/functions/list-&-map/list-and-map-concatenation/index.html create mode 100644 docs/0.16.0/ast-builder/functions/list-&-map/list-manipulation/index.html create mode 100644 docs/0.16.0/ast-builder/functions/math/basic-arithmetic/index.html create mode 100644 docs/0.16.0/ast-builder/functions/math/conversion/index.html create mode 100644 docs/0.16.0/ast-builder/functions/math/logarithmic-and-exponential/index.html create mode 100644 docs/0.16.0/ast-builder/functions/math/rounding/index.html create mode 100644 docs/0.16.0/ast-builder/functions/math/special-mathematical/index.html create mode 100644 docs/0.16.0/ast-builder/functions/math/trigonometric/index.html create mode 100644 docs/0.16.0/ast-builder/functions/others/null-handling/index.html create mode 100644 docs/0.16.0/ast-builder/functions/others/type-conversion/index.html create mode 100644 docs/0.16.0/ast-builder/functions/others/unique-identifier/index.html create mode 100644 docs/0.16.0/ast-builder/functions/text/case-conversion/index.html create mode 100644 docs/0.16.0/ast-builder/functions/text/character-conversion/index.html create mode 100644 docs/0.16.0/ast-builder/functions/text/padding/index.html create mode 100644 docs/0.16.0/ast-builder/functions/text/position-and-indexing/index.html create mode 100644 docs/0.16.0/ast-builder/functions/text/text-manipulation/index.html create mode 100644 docs/0.16.0/ast-builder/functions/text/trimming/index.html create mode 100644 docs/0.16.0/ast-builder/intro/index.html create mode 100644 docs/0.16.0/ast-builder/statements/data-manipulation/deleting-data/index.html create mode 100644 docs/0.16.0/ast-builder/statements/data-manipulation/inserting-data/index.html create mode 100644 docs/0.16.0/ast-builder/statements/data-manipulation/updating-data/index.html create mode 100644 docs/0.16.0/ast-builder/statements/querying/creating-derived-subqueries/index.html create mode 100644 docs/0.16.0/ast-builder/statements/querying/data-aggregation/index.html create mode 100644 docs/0.16.0/ast-builder/statements/querying/data-injection/index.html create mode 100644 docs/0.16.0/ast-builder/statements/querying/data-joining/index.html create mode 100644 docs/0.16.0/ast-builder/statements/querying/data-selection-and-projection/index.html create mode 100644 docs/0.16.0/ast-builder/statements/querying/data-sorting-and-limiting/index.html create mode 100644 docs/0.16.0/ast-builder/statements/querying/fetching-data-from-storage/index.html create mode 100644 docs/0.16.0/ast-builder/statements/querying/using-preloaded-data/index.html create mode 100644 docs/0.16.0/blog/archive/index.html create mode 100644 docs/0.16.0/blog/atom.xml create mode 100644 docs/0.16.0/blog/breaking-the-boundary-between-sql-and-nosql/index.html create mode 100644 docs/0.16.0/blog/index.html create mode 100644 docs/0.16.0/blog/release-v0.14/index.html create mode 100644 docs/0.16.0/blog/release-v0.15/index.html create mode 100644 docs/0.16.0/blog/revolutionizing-databases-by-unifying-query-interfaces/index.html create mode 100644 docs/0.16.0/blog/rss.xml create mode 100644 docs/0.16.0/blog/tags/automation/index.html create mode 100644 docs/0.16.0/blog/tags/chat-gpt/index.html create mode 100644 docs/0.16.0/blog/tags/database/index.html create mode 100644 docs/0.16.0/blog/tags/documentation/index.html create mode 100644 docs/0.16.0/blog/tags/gluesql/index.html create mode 100644 docs/0.16.0/blog/tags/index.html create mode 100644 docs/0.16.0/blog/tags/nosql/index.html create mode 100644 docs/0.16.0/blog/tags/proposal/index.html create mode 100644 docs/0.16.0/blog/tags/query-interface/index.html create mode 100644 docs/0.16.0/blog/tags/release-note/index.html create mode 100644 docs/0.16.0/blog/tags/sql/index.html create mode 100644 docs/0.16.0/blog/tags/tdd/index.html create mode 100644 docs/0.16.0/blog/tags/test-driven-documentation/index.html create mode 100644 docs/0.16.0/blog/tags/v-0-14/index.html create mode 100644 docs/0.16.0/blog/tags/v-0-15/index.html create mode 100644 docs/0.16.0/blog/test-driven-documentation/index.html create mode 100644 docs/0.16.0/getting-started/cli/index.html create mode 100644 docs/0.16.0/getting-started/javascript-web/index.html create mode 100644 docs/0.16.0/getting-started/nodejs/index.html create mode 100644 docs/0.16.0/getting-started/rust/index.html create mode 100644 docs/0.16.0/img/favicon.ico create mode 100644 docs/0.16.0/img/gluesql.jpg create mode 100644 docs/0.16.0/img/undraw_docusaurus_mountain.svg create mode 100644 docs/0.16.0/img/undraw_docusaurus_react.svg create mode 100644 docs/0.16.0/img/undraw_docusaurus_tree.svg create mode 100644 docs/0.16.0/index.html create mode 100644 docs/0.16.0/sitemap.xml create mode 100644 docs/0.16.0/sql-syntax/data-types/boolean/index.html create mode 100644 docs/0.16.0/sql-syntax/data-types/bytea/index.html create mode 100644 docs/0.16.0/sql-syntax/data-types/date/index.html create mode 100644 docs/0.16.0/sql-syntax/data-types/decimal/index.html create mode 100644 docs/0.16.0/sql-syntax/data-types/float/index.html create mode 100644 docs/0.16.0/sql-syntax/data-types/inet/index.html create mode 100644 docs/0.16.0/sql-syntax/data-types/integers/index.html create mode 100644 docs/0.16.0/sql-syntax/data-types/interval/index.html create mode 100644 docs/0.16.0/sql-syntax/data-types/list/index.html create mode 100644 docs/0.16.0/sql-syntax/data-types/map/index.html create mode 100644 docs/0.16.0/sql-syntax/data-types/text/index.html create mode 100644 docs/0.16.0/sql-syntax/data-types/time/index.html create mode 100644 docs/0.16.0/sql-syntax/data-types/timestamp/index.html create mode 100644 docs/0.16.0/sql-syntax/data-types/uuid/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/datetime/extract/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/datetime/format/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/datetime/now/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/datetime/to-date/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/datetime/to-time/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/datetime/to-timestamp/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/geometry/calc-distance/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/geometry/get-x/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/geometry/get-y/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/geometry/point/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/list-map/append/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/list-map/concat/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/list-map/prepend/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/list-map/slice/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/list-map/splice/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/math/abs/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/math/acos/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/math/asin/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/math/atan/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/math/ceil/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/math/cos/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/math/degrees/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/math/div/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/math/exp/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/math/floor/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/math/gcd/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/math/lcm/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/math/ln/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/math/log/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/math/log10/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/math/log2/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/math/mod/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/math/pi/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/math/power/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/math/radians/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/math/rand/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/math/round/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/math/sign/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/math/sin/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/math/sqrt/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/math/tan/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/others/cast/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/others/generate-uuid/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/others/ifnull/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/text/ascii/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/text/chr/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/text/concat-ws/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/text/concat/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/text/find-idx/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/text/initcap/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/text/left/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/text/lower/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/text/lpad/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/text/ltrim/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/text/position/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/text/repeat/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/text/reverse/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/text/right/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/text/rpad/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/text/rtrim/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/text/substr/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/text/trim/index.html create mode 100644 docs/0.16.0/sql-syntax/functions/text/upper/index.html create mode 100644 docs/0.16.0/sql-syntax/intro/index.html create mode 100644 docs/0.16.0/sql-syntax/statements/data-definition/alter-table/index.html create mode 100644 docs/0.16.0/sql-syntax/statements/data-definition/create-index/index.html create mode 100644 docs/0.16.0/sql-syntax/statements/data-definition/create-table/index.html create mode 100644 docs/0.16.0/sql-syntax/statements/data-definition/drop-index/index.html create mode 100644 docs/0.16.0/sql-syntax/statements/data-definition/drop-table/index.html create mode 100644 docs/0.16.0/sql-syntax/statements/data-manipulation/delete/index.html create mode 100644 docs/0.16.0/sql-syntax/statements/data-manipulation/insert/index.html create mode 100644 docs/0.16.0/sql-syntax/statements/data-manipulation/update/index.html create mode 100644 docs/0.16.0/sql-syntax/statements/metadata/data-dictionary/index.html create mode 100644 docs/0.16.0/sql-syntax/statements/metadata/show-tables/index.html create mode 100644 docs/0.16.0/sql-syntax/statements/querying/aggregation/index.html create mode 100644 docs/0.16.0/sql-syntax/statements/querying/join/index.html create mode 100644 docs/0.16.0/sql-syntax/statements/querying/limit/index.html create mode 100644 docs/0.16.0/sql-syntax/statements/querying/schemaless/index.html create mode 100644 docs/0.16.0/sql-syntax/statements/querying/where/index.html create mode 100644 docs/0.16.0/sql-syntax/statements/transaction/index.html create mode 100644 docs/0.16.0/storages/developing-custom-storages/intro/index.html create mode 100644 docs/0.16.0/storages/developing-custom-storages/store-traits/alter-table/index.html create mode 100644 docs/0.16.0/storages/developing-custom-storages/store-traits/custom-function-mut/index.html create mode 100644 docs/0.16.0/storages/developing-custom-storages/store-traits/custom-function/index.html create mode 100644 docs/0.16.0/storages/developing-custom-storages/store-traits/index-mut/index.html create mode 100644 docs/0.16.0/storages/developing-custom-storages/store-traits/index-trait/index.html create mode 100644 docs/0.16.0/storages/developing-custom-storages/store-traits/metadata/index.html create mode 100644 docs/0.16.0/storages/developing-custom-storages/store-traits/store-mut/index.html create mode 100644 docs/0.16.0/storages/developing-custom-storages/store-traits/store/index.html create mode 100644 docs/0.16.0/storages/developing-custom-storages/store-traits/transaction/index.html create mode 100644 docs/0.16.0/storages/developing-custom-storages/using-test-suite/index.html create mode 100644 docs/0.16.0/storages/intro/index.html create mode 100644 docs/0.16.0/storages/supported-storages/composite-storage/index.html create mode 100644 docs/0.16.0/storages/supported-storages/csv-storage/index.html create mode 100644 docs/0.16.0/storages/supported-storages/idb-storage/index.html create mode 100644 docs/0.16.0/storages/supported-storages/json-storage/index.html create mode 100644 docs/0.16.0/storages/supported-storages/memory-storage/index.html create mode 100644 docs/0.16.0/storages/supported-storages/parquet-storage/index.html create mode 100644 docs/0.16.0/storages/supported-storages/shared-memory-storage/index.html create mode 100644 docs/0.16.0/storages/supported-storages/sled-storage/index.html create mode 100644 docs/0.16.0/storages/supported-storages/web-storage/index.html diff --git a/docs/0.16.0/.nojekyll b/docs/0.16.0/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/docs/0.16.0/404.html b/docs/0.16.0/404.html new file mode 100644 index 00000000..cfb33892 --- /dev/null +++ b/docs/0.16.0/404.html @@ -0,0 +1,17 @@ + + + + + +Page Not Found | GlueSQL + + + + + +
+
Skip to main content

Page Not Found

We could not find what you were looking for.

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

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/assets/css/styles.1b097026.css b/docs/0.16.0/assets/css/styles.1b097026.css new file mode 100644 index 00000000..da6a5dfc --- /dev/null +++ b/docs/0.16.0/assets/css/styles.1b097026.css @@ -0,0 +1 @@ +@import url(https://fonts.googleapis.com/css2?family=Fira+Sans:wght@400;500;600&display=swap);@import url(https://fonts.googleapis.com/css2?family=Alfa+Slab+One&display=swap);.col,.container{padding:0 var(--ifm-spacing-horizontal);width:100%}.markdown>h2,.markdown>h3,.markdown>h4,.markdown>h5,.markdown>h6{margin-bottom:calc(var(--ifm-heading-vertical-rhythm-bottom)*var(--ifm-leading))}body,ol ol,ol ul,ul ol,ul ul{margin:0}pre,table{overflow:auto}blockquote,pre{margin:0 0 var(--ifm-spacing-vertical)}.breadcrumbs__link,.button{transition-timing-function:var(--ifm-transition-timing-default)}.button,code{vertical-align:middle}.button--outline.button--active,.button--outline:active,.button--outline:hover,:root{--ifm-button-color:var(--ifm-font-color-base-inverse)}.menu__link:hover,a{transition:color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.navbar--dark,:root{--ifm-navbar-link-hover-color:var(--ifm-color-primary)}.menu,.navbar-sidebar{overflow-x:hidden}:root,html[data-theme=dark]{--ifm-color-emphasis-500:var(--ifm-color-gray-500)}.markdown li,article h1,body{word-wrap:break-word}.toggleButton_gllP,html{-webkit-tap-highlight-color:transparent}.clean-list,.containsTaskList_mC6p,.details_lb9f>summary,.dropdown__menu,.menu__list{list-style:none}:root{--ifm-color-scheme:light;--ifm-dark-value:10%;--ifm-darker-value:15%;--ifm-darkest-value:30%;--ifm-light-value:15%;--ifm-lighter-value:30%;--ifm-lightest-value:50%;--ifm-contrast-background-value:90%;--ifm-contrast-foreground-value:70%;--ifm-contrast-background-dark-value:70%;--ifm-contrast-foreground-dark-value:90%;--ifm-color-primary:#3578e5;--ifm-color-secondary:#ebedf0;--ifm-color-success:#00a400;--ifm-color-info:#54c7ec;--ifm-color-warning:#ffba00;--ifm-color-danger:#fa383e;--ifm-color-primary-dark:#306cce;--ifm-color-primary-darker:#2d66c3;--ifm-color-primary-darkest:#2554a0;--ifm-color-primary-light:#538ce9;--ifm-color-primary-lighter:#72a1ed;--ifm-color-primary-lightest:#9abcf2;--ifm-color-primary-contrast-background:#ebf2fc;--ifm-color-primary-contrast-foreground:#102445;--ifm-color-secondary-dark:#d4d5d8;--ifm-color-secondary-darker:#c8c9cc;--ifm-color-secondary-darkest:#a4a6a8;--ifm-color-secondary-light:#eef0f2;--ifm-color-secondary-lighter:#f1f2f5;--ifm-color-secondary-lightest:#f5f6f8;--ifm-color-secondary-contrast-background:#fdfdfe;--ifm-color-secondary-contrast-foreground:#474748;--ifm-color-success-dark:#009400;--ifm-color-success-darker:#008b00;--ifm-color-success-darkest:#007300;--ifm-color-success-light:#26b226;--ifm-color-success-lighter:#4dbf4d;--ifm-color-success-lightest:#80d280;--ifm-color-success-contrast-background:#e6f6e6;--ifm-color-success-contrast-foreground:#003100;--ifm-color-info-dark:#4cb3d4;--ifm-color-info-darker:#47a9c9;--ifm-color-info-darkest:#3b8ba5;--ifm-color-info-light:#6ecfef;--ifm-color-info-lighter:#87d8f2;--ifm-color-info-lightest:#aae3f6;--ifm-color-info-contrast-background:#eef9fd;--ifm-color-info-contrast-foreground:#193c47;--ifm-color-warning-dark:#e6a700;--ifm-color-warning-darker:#d99e00;--ifm-color-warning-darkest:#b38200;--ifm-color-warning-light:#ffc426;--ifm-color-warning-lighter:#ffcf4d;--ifm-color-warning-lightest:#ffdd80;--ifm-color-warning-contrast-background:#fff8e6;--ifm-color-warning-contrast-foreground:#4d3800;--ifm-color-danger-dark:#e13238;--ifm-color-danger-darker:#d53035;--ifm-color-danger-darkest:#af272b;--ifm-color-danger-light:#fb565b;--ifm-color-danger-lighter:#fb7478;--ifm-color-danger-lightest:#fd9c9f;--ifm-color-danger-contrast-background:#ffebec;--ifm-color-danger-contrast-foreground:#4b1113;--ifm-color-white:#fff;--ifm-color-black:#000;--ifm-color-gray-0:var(--ifm-color-white);--ifm-color-gray-100:#f5f6f7;--ifm-color-gray-200:#ebedf0;--ifm-color-gray-300:#dadde1;--ifm-color-gray-400:#ccd0d5;--ifm-color-gray-500:#bec3c9;--ifm-color-gray-600:#8d949e;--ifm-color-gray-700:#606770;--ifm-color-gray-800:#444950;--ifm-color-gray-900:#1c1e21;--ifm-color-gray-1000:var(--ifm-color-black);--ifm-color-emphasis-0:var(--ifm-color-gray-0);--ifm-color-emphasis-100:var(--ifm-color-gray-100);--ifm-color-emphasis-200:var(--ifm-color-gray-200);--ifm-color-emphasis-300:var(--ifm-color-gray-300);--ifm-color-emphasis-400:var(--ifm-color-gray-400);--ifm-color-emphasis-600:var(--ifm-color-gray-600);--ifm-color-emphasis-700:var(--ifm-color-gray-700);--ifm-color-emphasis-800:var(--ifm-color-gray-800);--ifm-color-emphasis-900:var(--ifm-color-gray-900);--ifm-color-emphasis-1000:var(--ifm-color-gray-1000);--ifm-color-content:var(--ifm-color-emphasis-900);--ifm-color-content-inverse:var(--ifm-color-emphasis-0);--ifm-color-content-secondary:#525860;--ifm-background-color:#0000;--ifm-background-surface-color:var(--ifm-color-content-inverse);--ifm-global-border-width:1px;--ifm-global-radius:0.4rem;--ifm-hover-overlay:#0000000d;--ifm-font-color-base:var(--ifm-color-content);--ifm-font-color-base-inverse:var(--ifm-color-content-inverse);--ifm-font-color-secondary:var(--ifm-color-content-secondary);--ifm-font-family-base:system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,sans-serif,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";--ifm-font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--ifm-font-size-base:100%;--ifm-font-weight-light:300;--ifm-font-weight-normal:400;--ifm-font-weight-semibold:500;--ifm-font-weight-bold:700;--ifm-font-weight-base:var(--ifm-font-weight-normal);--ifm-line-height-base:1.65;--ifm-global-spacing:1rem;--ifm-spacing-vertical:var(--ifm-global-spacing);--ifm-spacing-horizontal:var(--ifm-global-spacing);--ifm-transition-fast:200ms;--ifm-transition-slow:400ms;--ifm-transition-timing-default:cubic-bezier(0.08,0.52,0.52,1);--ifm-global-shadow-lw:0 1px 2px 0 #0000001a;--ifm-global-shadow-md:0 5px 40px #0003;--ifm-global-shadow-tl:0 12px 28px 0 #0003,0 2px 4px 0 #0000001a;--ifm-z-index-dropdown:100;--ifm-z-index-fixed:200;--ifm-z-index-overlay:400;--ifm-container-width:1140px;--ifm-container-width-xl:1320px;--ifm-code-background:#f6f7f8;--ifm-code-border-radius:var(--ifm-global-radius);--ifm-code-font-size:90%;--ifm-code-padding-horizontal:0.1rem;--ifm-code-padding-vertical:0.1rem;--ifm-pre-background:var(--ifm-code-background);--ifm-pre-border-radius:var(--ifm-code-border-radius);--ifm-pre-color:inherit;--ifm-pre-line-height:1.45;--ifm-pre-padding:1rem;--ifm-heading-color:inherit;--ifm-heading-margin-top:0;--ifm-heading-margin-bottom:var(--ifm-spacing-vertical);--ifm-heading-font-family:var(--ifm-font-family-base);--ifm-heading-font-weight:var(--ifm-font-weight-bold);--ifm-heading-line-height:1.25;--ifm-h1-font-size:2rem;--ifm-h2-font-size:1.5rem;--ifm-h3-font-size:1.25rem;--ifm-h4-font-size:1rem;--ifm-h5-font-size:0.875rem;--ifm-h6-font-size:0.85rem;--ifm-image-alignment-padding:1.25rem;--ifm-leading-desktop:1.25;--ifm-leading:calc(var(--ifm-leading-desktop)*1rem);--ifm-list-left-padding:2rem;--ifm-list-margin:1rem;--ifm-list-item-margin:0.25rem;--ifm-list-paragraph-margin:1rem;--ifm-table-cell-padding:0.75rem;--ifm-table-background:#0000;--ifm-table-stripe-background:#00000008;--ifm-table-border-width:1px;--ifm-table-border-color:var(--ifm-color-emphasis-300);--ifm-table-head-background:inherit;--ifm-table-head-color:inherit;--ifm-table-head-font-weight:var(--ifm-font-weight-bold);--ifm-table-cell-color:inherit;--ifm-link-color:var(--ifm-color-primary);--ifm-link-decoration:none;--ifm-link-hover-color:var(--ifm-link-color);--ifm-link-hover-decoration:underline;--ifm-paragraph-margin-bottom:var(--ifm-leading);--ifm-blockquote-font-size:var(--ifm-font-size-base);--ifm-blockquote-border-left-width:2px;--ifm-blockquote-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-blockquote-padding-vertical:0;--ifm-blockquote-shadow:none;--ifm-blockquote-color:var(--ifm-color-emphasis-800);--ifm-blockquote-border-color:var(--ifm-color-emphasis-300);--ifm-hr-background-color:var(--ifm-color-emphasis-500);--ifm-hr-height:1px;--ifm-hr-margin-vertical:1.5rem;--ifm-scrollbar-size:7px;--ifm-scrollbar-track-background-color:#f1f1f1;--ifm-scrollbar-thumb-background-color:silver;--ifm-scrollbar-thumb-hover-background-color:#a7a7a7;--ifm-alert-background-color:inherit;--ifm-alert-border-color:inherit;--ifm-alert-border-radius:var(--ifm-global-radius);--ifm-alert-border-width:0px;--ifm-alert-border-left-width:5px;--ifm-alert-color:var(--ifm-font-color-base);--ifm-alert-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-alert-padding-vertical:var(--ifm-spacing-vertical);--ifm-alert-shadow:var(--ifm-global-shadow-lw);--ifm-avatar-intro-margin:1rem;--ifm-avatar-intro-alignment:inherit;--ifm-avatar-photo-size:3rem;--ifm-badge-background-color:inherit;--ifm-badge-border-color:inherit;--ifm-badge-border-radius:var(--ifm-global-radius);--ifm-badge-border-width:var(--ifm-global-border-width);--ifm-badge-color:var(--ifm-color-white);--ifm-badge-padding-horizontal:calc(var(--ifm-spacing-horizontal)*0.5);--ifm-badge-padding-vertical:calc(var(--ifm-spacing-vertical)*0.25);--ifm-breadcrumb-border-radius:1.5rem;--ifm-breadcrumb-spacing:0.5rem;--ifm-breadcrumb-color-active:var(--ifm-color-primary);--ifm-breadcrumb-item-background-active:var(--ifm-hover-overlay);--ifm-breadcrumb-padding-horizontal:0.8rem;--ifm-breadcrumb-padding-vertical:0.4rem;--ifm-breadcrumb-size-multiplier:1;--ifm-breadcrumb-separator:url('data:image/svg+xml;utf8,');--ifm-breadcrumb-separator-filter:none;--ifm-breadcrumb-separator-size:0.5rem;--ifm-breadcrumb-separator-size-multiplier:1.25;--ifm-button-background-color:inherit;--ifm-button-border-color:var(--ifm-button-background-color);--ifm-button-border-width:var(--ifm-global-border-width);--ifm-button-font-weight:var(--ifm-font-weight-bold);--ifm-button-padding-horizontal:1.5rem;--ifm-button-padding-vertical:0.375rem;--ifm-button-size-multiplier:1;--ifm-button-transition-duration:var(--ifm-transition-fast);--ifm-button-border-radius:calc(var(--ifm-global-radius)*var(--ifm-button-size-multiplier));--ifm-button-group-spacing:2px;--ifm-card-background-color:var(--ifm-background-surface-color);--ifm-card-border-radius:calc(var(--ifm-global-radius)*2);--ifm-card-horizontal-spacing:var(--ifm-global-spacing);--ifm-card-vertical-spacing:var(--ifm-global-spacing);--ifm-toc-border-color:var(--ifm-color-emphasis-300);--ifm-toc-link-color:var(--ifm-color-content-secondary);--ifm-toc-padding-vertical:0.5rem;--ifm-toc-padding-horizontal:0.5rem;--ifm-dropdown-background-color:var(--ifm-background-surface-color);--ifm-dropdown-font-weight:var(--ifm-font-weight-semibold);--ifm-dropdown-link-color:var(--ifm-font-color-base);--ifm-dropdown-hover-background-color:var(--ifm-hover-overlay);--ifm-footer-background-color:var(--ifm-color-emphasis-100);--ifm-footer-color:inherit;--ifm-footer-link-color:var(--ifm-color-emphasis-700);--ifm-footer-link-hover-color:var(--ifm-color-primary);--ifm-footer-link-horizontal-spacing:0.5rem;--ifm-footer-padding-horizontal:calc(var(--ifm-spacing-horizontal)*2);--ifm-footer-padding-vertical:calc(var(--ifm-spacing-vertical)*2);--ifm-footer-title-color:inherit;--ifm-footer-logo-max-width:min(30rem,90vw);--ifm-hero-background-color:var(--ifm-background-surface-color);--ifm-hero-text-color:var(--ifm-color-emphasis-800);--ifm-menu-color:var(--ifm-color-emphasis-700);--ifm-menu-color-active:var(--ifm-color-primary);--ifm-menu-color-background-active:var(--ifm-hover-overlay);--ifm-menu-color-background-hover:var(--ifm-hover-overlay);--ifm-menu-link-padding-horizontal:0.75rem;--ifm-menu-link-padding-vertical:0.375rem;--ifm-menu-link-sublist-icon:url('data:image/svg+xml;utf8,');--ifm-menu-link-sublist-icon-filter:none;--ifm-navbar-background-color:var(--ifm-background-surface-color);--ifm-navbar-height:3.75rem;--ifm-navbar-item-padding-horizontal:0.75rem;--ifm-navbar-item-padding-vertical:0.25rem;--ifm-navbar-link-color:var(--ifm-font-color-base);--ifm-navbar-link-active-color:var(--ifm-link-color);--ifm-navbar-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-navbar-padding-vertical:calc(var(--ifm-spacing-vertical)*0.5);--ifm-navbar-shadow:var(--ifm-global-shadow-lw);--ifm-navbar-search-input-background-color:var(--ifm-color-emphasis-200);--ifm-navbar-search-input-color:var(--ifm-color-emphasis-800);--ifm-navbar-search-input-placeholder-color:var(--ifm-color-emphasis-500);--ifm-navbar-search-input-icon:url('data:image/svg+xml;utf8,');--ifm-navbar-sidebar-width:83vw;--ifm-pagination-border-radius:var(--ifm-global-radius);--ifm-pagination-color-active:var(--ifm-color-primary);--ifm-pagination-font-size:1rem;--ifm-pagination-item-active-background:var(--ifm-hover-overlay);--ifm-pagination-page-spacing:0.2em;--ifm-pagination-padding-horizontal:calc(var(--ifm-spacing-horizontal)*1);--ifm-pagination-padding-vertical:calc(var(--ifm-spacing-vertical)*0.25);--ifm-pagination-nav-border-radius:var(--ifm-global-radius);--ifm-pagination-nav-color-hover:var(--ifm-color-primary);--ifm-pills-color-active:var(--ifm-color-primary);--ifm-pills-color-background-active:var(--ifm-hover-overlay);--ifm-pills-spacing:0.125rem;--ifm-tabs-color:var(--ifm-font-color-secondary);--ifm-tabs-color-active:var(--ifm-color-primary);--ifm-tabs-color-active-border:var(--ifm-tabs-color-active);--ifm-tabs-padding-horizontal:1rem;--ifm-tabs-padding-vertical:1rem;--docusaurus-progress-bar-color:var(--ifm-color-primary);--ifm-color-primary:#0077be;--ifm-color-primary-dark:#005fa3;--ifm-color-primary-darker:#004c87;--ifm-color-primary-darkest:#003c6b;--ifm-color-primary-light:#0093e8;--ifm-color-primary-lighter:#00a3ff;--ifm-color-primary-lightest:#00baff;--ifm-code-font-size:95%;--docusaurus-highlighted-code-line-bg:#0000001a;--docusaurus-announcement-bar-height:auto;--docusaurus-collapse-button-bg:#0000;--docusaurus-collapse-button-bg-hover:#0000001a;--doc-sidebar-width:300px;--doc-sidebar-hidden-width:30px;--docusaurus-tag-list-border:var(--ifm-color-emphasis-300)}.badge--danger,.badge--info,.badge--primary,.badge--secondary,.badge--success,.badge--warning{--ifm-badge-border-color:var(--ifm-badge-background-color)}.button--link,.button--outline{--ifm-button-background-color:#0000}*{box-sizing:border-box}html{-webkit-font-smoothing:antialiased;-webkit-text-size-adjust:100%;text-size-adjust:100%;background-color:var(--ifm-background-color);color:var(--ifm-font-color-base);color-scheme:var(--ifm-color-scheme);font:var(--ifm-font-size-base)/var(--ifm-line-height-base) var(--ifm-font-family-base);text-rendering:optimizelegibility}iframe{border:0;color-scheme:auto}.container{margin:0 auto;max-width:var(--ifm-container-width)}.container--fluid{max-width:inherit}.row{display:flex;flex-wrap:wrap;margin:0 calc(var(--ifm-spacing-horizontal)*-1)}.margin-bottom--none,.margin-vert--none,.markdown>:last-child{margin-bottom:0!important}.margin-top--none,.margin-vert--none{margin-top:0!important}.row--no-gutters{margin-left:0;margin-right:0}.margin-horiz--none,.margin-right--none{margin-right:0!important}.row--no-gutters>.col{padding-left:0;padding-right:0}.row--align-top{align-items:flex-start}.row--align-bottom{align-items:flex-end}.menuExternalLink_NmtK,.row--align-center{align-items:center}.row--align-stretch{align-items:stretch}.row--align-baseline{align-items:baseline}.col{--ifm-col-width:100%;flex:1 0;margin-left:0;max-width:var(--ifm-col-width)}.padding-bottom--none,.padding-vert--none{padding-bottom:0!important}.padding-top--none,.padding-vert--none{padding-top:0!important}.padding-horiz--none,.padding-left--none{padding-left:0!important}.padding-horiz--none,.padding-right--none{padding-right:0!important}.col[class*=col--]{flex:0 0 var(--ifm-col-width)}.col--1{--ifm-col-width:8.33333%}.col--offset-1{margin-left:8.33333%}.col--2{--ifm-col-width:16.66667%}.col--offset-2{margin-left:16.66667%}.col--3{--ifm-col-width:25%}.col--offset-3{margin-left:25%}.col--4{--ifm-col-width:33.33333%}.col--offset-4{margin-left:33.33333%}.col--5{--ifm-col-width:41.66667%}.col--offset-5{margin-left:41.66667%}.col--6{--ifm-col-width:50%}.col--offset-6{margin-left:50%}.col--7{--ifm-col-width:58.33333%}.col--offset-7{margin-left:58.33333%}.col--8{--ifm-col-width:66.66667%}.col--offset-8{margin-left:66.66667%}.col--9{--ifm-col-width:75%}.col--offset-9{margin-left:75%}.col--10{--ifm-col-width:83.33333%}.col--offset-10{margin-left:83.33333%}.col--11{--ifm-col-width:91.66667%}.col--offset-11{margin-left:91.66667%}.col--12{--ifm-col-width:100%}.col--offset-12{margin-left:100%}.margin-horiz--none,.margin-left--none{margin-left:0!important}.margin--none{margin:0!important}.margin-bottom--xs,.margin-vert--xs{margin-bottom:.25rem!important}.margin-top--xs,.margin-vert--xs{margin-top:.25rem!important}.margin-horiz--xs,.margin-left--xs{margin-left:.25rem!important}.margin-horiz--xs,.margin-right--xs{margin-right:.25rem!important}.margin--xs{margin:.25rem!important}.margin-bottom--sm,.margin-vert--sm{margin-bottom:.5rem!important}.margin-top--sm,.margin-vert--sm{margin-top:.5rem!important}.margin-horiz--sm,.margin-left--sm{margin-left:.5rem!important}.margin-horiz--sm,.margin-right--sm{margin-right:.5rem!important}.margin--sm{margin:.5rem!important}.margin-bottom--md,.margin-vert--md{margin-bottom:1rem!important}.margin-top--md,.margin-vert--md{margin-top:1rem!important}.margin-horiz--md,.margin-left--md{margin-left:1rem!important}.margin-horiz--md,.margin-right--md{margin-right:1rem!important}.margin--md{margin:1rem!important}.margin-bottom--lg,.margin-vert--lg{margin-bottom:2rem!important}.margin-top--lg,.margin-vert--lg{margin-top:2rem!important}.margin-horiz--lg,.margin-left--lg{margin-left:2rem!important}.margin-horiz--lg,.margin-right--lg{margin-right:2rem!important}.margin--lg{margin:2rem!important}.margin-bottom--xl,.margin-vert--xl{margin-bottom:5rem!important}.margin-top--xl,.margin-vert--xl{margin-top:5rem!important}.margin-horiz--xl,.margin-left--xl{margin-left:5rem!important}.margin-horiz--xl,.margin-right--xl{margin-right:5rem!important}.margin--xl{margin:5rem!important}.padding--none{padding:0!important}.padding-bottom--xs,.padding-vert--xs{padding-bottom:.25rem!important}.padding-top--xs,.padding-vert--xs{padding-top:.25rem!important}.padding-horiz--xs,.padding-left--xs{padding-left:.25rem!important}.padding-horiz--xs,.padding-right--xs{padding-right:.25rem!important}.padding--xs{padding:.25rem!important}.padding-bottom--sm,.padding-vert--sm{padding-bottom:.5rem!important}.padding-top--sm,.padding-vert--sm{padding-top:.5rem!important}.padding-horiz--sm,.padding-left--sm{padding-left:.5rem!important}.padding-horiz--sm,.padding-right--sm{padding-right:.5rem!important}.padding--sm{padding:.5rem!important}.padding-bottom--md,.padding-vert--md{padding-bottom:1rem!important}.padding-top--md,.padding-vert--md{padding-top:1rem!important}.padding-horiz--md,.padding-left--md{padding-left:1rem!important}.padding-horiz--md,.padding-right--md{padding-right:1rem!important}.padding--md{padding:1rem!important}.padding-bottom--lg,.padding-vert--lg{padding-bottom:2rem!important}.padding-top--lg,.padding-vert--lg{padding-top:2rem!important}.padding-horiz--lg,.padding-left--lg{padding-left:2rem!important}.padding-horiz--lg,.padding-right--lg{padding-right:2rem!important}.padding--lg{padding:2rem!important}.padding-bottom--xl,.padding-vert--xl{padding-bottom:5rem!important}.padding-top--xl,.padding-vert--xl{padding-top:5rem!important}.padding-horiz--xl,.padding-left--xl{padding-left:5rem!important}.padding-horiz--xl,.padding-right--xl{padding-right:5rem!important}.padding--xl{padding:5rem!important}code{background-color:var(--ifm-code-background);border:.1rem solid #0000001a;border-radius:var(--ifm-code-border-radius);font-family:var(--ifm-font-family-monospace);font-size:var(--ifm-code-font-size);padding:var(--ifm-code-padding-vertical) var(--ifm-code-padding-horizontal)}a code{color:inherit}pre{background-color:var(--ifm-pre-background);border-radius:var(--ifm-pre-border-radius);color:var(--ifm-pre-color);font:var(--ifm-code-font-size)/var(--ifm-pre-line-height) var(--ifm-font-family-monospace);padding:var(--ifm-pre-padding)}pre code{background-color:initial;border:none;font-size:100%;line-height:inherit;padding:0}kbd{background-color:var(--ifm-color-emphasis-0);border:1px solid var(--ifm-color-emphasis-400);border-radius:.2rem;box-shadow:inset 0 -1px 0 var(--ifm-color-emphasis-400);color:var(--ifm-color-emphasis-800);font:80% var(--ifm-font-family-monospace);padding:.15rem .3rem}h1,h2,h3,h4,h5,h6{color:var(--ifm-heading-color);font-family:var(--ifm-heading-font-family);font-weight:var(--ifm-heading-font-weight);line-height:var(--ifm-heading-line-height);margin:var(--ifm-heading-margin-top) 0 var(--ifm-heading-margin-bottom) 0}h1{font-size:var(--ifm-h1-font-size)}h2{font-size:var(--ifm-h2-font-size)}h3{font-size:var(--ifm-h3-font-size)}h4{font-size:var(--ifm-h4-font-size)}h5{font-size:var(--ifm-h5-font-size)}h6{font-size:var(--ifm-h6-font-size)}img{max-width:100%}img[align=right]{padding-left:var(--image-alignment-padding)}img[align=left]{padding-right:var(--image-alignment-padding)}.markdown{--ifm-h1-vertical-rhythm-top:3;--ifm-h2-vertical-rhythm-top:2;--ifm-h3-vertical-rhythm-top:1.5;--ifm-heading-vertical-rhythm-top:1.25;--ifm-h1-vertical-rhythm-bottom:1.25;--ifm-heading-vertical-rhythm-bottom:1}.markdown:after,.markdown:before{content:"";display:table}.markdown:after{clear:both}.markdown h1:first-child{--ifm-h1-font-size:3rem;margin-bottom:calc(var(--ifm-h1-vertical-rhythm-bottom)*var(--ifm-leading))}.markdown>h2{--ifm-h2-font-size:2rem;margin-top:calc(var(--ifm-h2-vertical-rhythm-top)*var(--ifm-leading))}.markdown>h3{--ifm-h3-font-size:1.5rem;margin-top:calc(var(--ifm-h3-vertical-rhythm-top)*var(--ifm-leading))}.markdown>h4,.markdown>h5,.markdown>h6{margin-top:calc(var(--ifm-heading-vertical-rhythm-top)*var(--ifm-leading))}.markdown>p,.markdown>pre,.markdown>ul{margin-bottom:var(--ifm-leading)}.markdown li>p{margin-top:var(--ifm-list-paragraph-margin)}.markdown li+li{margin-top:var(--ifm-list-item-margin)}ol,ul{margin:0 0 var(--ifm-list-margin);padding-left:var(--ifm-list-left-padding)}ol ol,ul ol{list-style-type:lower-roman}ol ol ol,ol ul ol,ul ol ol,ul ul ol{list-style-type:lower-alpha}table{border-collapse:collapse;display:block;margin-bottom:var(--ifm-spacing-vertical)}table thead tr{border-bottom:2px solid var(--ifm-table-border-color)}table thead,table tr:nth-child(2n){background-color:var(--ifm-table-stripe-background)}table tr{background-color:var(--ifm-table-background);border-top:var(--ifm-table-border-width) solid var(--ifm-table-border-color)}table td,table th{border:var(--ifm-table-border-width) solid var(--ifm-table-border-color);padding:var(--ifm-table-cell-padding)}table th{background-color:var(--ifm-table-head-background);color:var(--ifm-table-head-color);font-weight:var(--ifm-table-head-font-weight)}table td{color:var(--ifm-table-cell-color)}strong{font-weight:var(--ifm-font-weight-bold)}a{color:var(--ifm-link-color);text-decoration:var(--ifm-link-decoration)}a:hover{color:var(--ifm-link-hover-color);text-decoration:var(--ifm-link-hover-decoration)}.button:hover,.text--no-decoration,.text--no-decoration:hover,a:not([href]){text-decoration:none}p{margin:0 0 var(--ifm-paragraph-margin-bottom)}blockquote{border-left:var(--ifm-blockquote-border-left-width) solid var(--ifm-blockquote-border-color);box-shadow:var(--ifm-blockquote-shadow);color:var(--ifm-blockquote-color);font-size:var(--ifm-blockquote-font-size);padding:var(--ifm-blockquote-padding-vertical) var(--ifm-blockquote-padding-horizontal)}blockquote>:first-child{margin-top:0}blockquote>:last-child{margin-bottom:0}hr{background-color:var(--ifm-hr-background-color);border:0;height:var(--ifm-hr-height);margin:var(--ifm-hr-margin-vertical) 0}.shadow--lw{box-shadow:var(--ifm-global-shadow-lw)!important}.shadow--md{box-shadow:var(--ifm-global-shadow-md)!important}.shadow--tl{box-shadow:var(--ifm-global-shadow-tl)!important}.text--primary,.wordWrapButtonEnabled_EoeP .wordWrapButtonIcon_Bwma{color:var(--ifm-color-primary)}.text--secondary{color:var(--ifm-color-secondary)}.text--success{color:var(--ifm-color-success)}.text--info{color:var(--ifm-color-info)}.text--warning{color:var(--ifm-color-warning)}.text--danger{color:var(--ifm-color-danger)}.text--center{text-align:center}.text--left{text-align:left}.text--justify{text-align:justify}.text--right{text-align:right}.text--capitalize{text-transform:capitalize}.text--lowercase{text-transform:lowercase}.admonitionHeading_tbUL,.alert__heading,.text--uppercase{text-transform:uppercase}.text--light{font-weight:var(--ifm-font-weight-light)}.text--normal{font-weight:var(--ifm-font-weight-normal)}.text--semibold{font-weight:var(--ifm-font-weight-semibold)}.text--bold{font-weight:var(--ifm-font-weight-bold)}.text--italic{font-style:italic}.text--truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text--break{word-wrap:break-word!important;word-break:break-word!important}.clean-btn{background:none;border:none;color:inherit;cursor:pointer;font-family:inherit;padding:0}.alert,.alert .close{color:var(--ifm-alert-foreground-color)}.clean-list{padding-left:0}.alert--primary{--ifm-alert-background-color:var(--ifm-color-primary-contrast-background);--ifm-alert-background-color-highlight:#3578e526;--ifm-alert-foreground-color:var(--ifm-color-primary-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-primary-dark)}.alert--secondary{--ifm-alert-background-color:var(--ifm-color-secondary-contrast-background);--ifm-alert-background-color-highlight:#ebedf026;--ifm-alert-foreground-color:var(--ifm-color-secondary-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-secondary-dark)}.alert--success{--ifm-alert-background-color:var(--ifm-color-success-contrast-background);--ifm-alert-background-color-highlight:#00a40026;--ifm-alert-foreground-color:var(--ifm-color-success-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-success-dark)}.alert--info{--ifm-alert-background-color:var(--ifm-color-info-contrast-background);--ifm-alert-background-color-highlight:#54c7ec26;--ifm-alert-foreground-color:var(--ifm-color-info-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-info-dark)}.alert--warning{--ifm-alert-background-color:var(--ifm-color-warning-contrast-background);--ifm-alert-background-color-highlight:#ffba0026;--ifm-alert-foreground-color:var(--ifm-color-warning-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-warning-dark)}.alert--danger{--ifm-alert-background-color:var(--ifm-color-danger-contrast-background);--ifm-alert-background-color-highlight:#fa383e26;--ifm-alert-foreground-color:var(--ifm-color-danger-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-danger-dark)}.alert{--ifm-code-background:var(--ifm-alert-background-color-highlight);--ifm-link-color:var(--ifm-alert-foreground-color);--ifm-link-hover-color:var(--ifm-alert-foreground-color);--ifm-link-decoration:underline;--ifm-tabs-color:var(--ifm-alert-foreground-color);--ifm-tabs-color-active:var(--ifm-alert-foreground-color);--ifm-tabs-color-active-border:var(--ifm-alert-border-color);background-color:var(--ifm-alert-background-color);border:var(--ifm-alert-border-width) solid var(--ifm-alert-border-color);border-left-width:var(--ifm-alert-border-left-width);border-radius:var(--ifm-alert-border-radius);box-shadow:var(--ifm-alert-shadow);padding:var(--ifm-alert-padding-vertical) var(--ifm-alert-padding-horizontal)}.alert__heading{align-items:center;display:flex;font:700 var(--ifm-h5-font-size)/var(--ifm-heading-line-height) var(--ifm-heading-font-family);margin-bottom:.5rem}.alert__icon{display:inline-flex;margin-right:.4em}.alert__icon svg{fill:var(--ifm-alert-foreground-color);stroke:var(--ifm-alert-foreground-color);stroke-width:0}.alert .close{margin:calc(var(--ifm-alert-padding-vertical)*-1) calc(var(--ifm-alert-padding-horizontal)*-1) 0 0;opacity:.75}.alert .close:focus,.alert .close:hover{opacity:1}.alert a{text-decoration-color:var(--ifm-alert-border-color)}.alert a:hover{text-decoration-thickness:2px}.avatar{column-gap:var(--ifm-avatar-intro-margin);display:flex}.avatar__photo{border-radius:50%;display:block;height:var(--ifm-avatar-photo-size);overflow:hidden;width:var(--ifm-avatar-photo-size)}.card--full-height,.navbar__logo img,body,html{height:100%}.avatar__photo--sm{--ifm-avatar-photo-size:2rem}.avatar__photo--lg{--ifm-avatar-photo-size:4rem}.avatar__photo--xl{--ifm-avatar-photo-size:6rem}.avatar__intro{display:flex;flex:1 1;flex-direction:column;justify-content:center;text-align:var(--ifm-avatar-intro-alignment)}.badge,.breadcrumbs__item,.breadcrumbs__link,.button,.dropdown>.navbar__link:after{display:inline-block}.avatar__name{font:700 var(--ifm-h4-font-size)/var(--ifm-heading-line-height) var(--ifm-font-family-base)}.avatar__subtitle{margin-top:.25rem}.avatar--vertical{--ifm-avatar-intro-alignment:center;--ifm-avatar-intro-margin:0.5rem;align-items:center;flex-direction:column}.badge{background-color:var(--ifm-badge-background-color);border:var(--ifm-badge-border-width) solid var(--ifm-badge-border-color);border-radius:var(--ifm-badge-border-radius);color:var(--ifm-badge-color);font-size:75%;font-weight:var(--ifm-font-weight-bold);line-height:1;padding:var(--ifm-badge-padding-vertical) var(--ifm-badge-padding-horizontal)}.badge--primary{--ifm-badge-background-color:var(--ifm-color-primary)}.badge--secondary{--ifm-badge-background-color:var(--ifm-color-secondary);color:var(--ifm-color-black)}.breadcrumbs__link,.button.button--secondary.button--outline:not(.button--active):not(:hover){color:var(--ifm-font-color-base)}.badge--success{--ifm-badge-background-color:var(--ifm-color-success)}.badge--info{--ifm-badge-background-color:var(--ifm-color-info)}.badge--warning{--ifm-badge-background-color:var(--ifm-color-warning)}.badge--danger{--ifm-badge-background-color:var(--ifm-color-danger)}.breadcrumbs{margin-bottom:0;padding-left:0}.breadcrumbs__item:not(:last-child):after{background:var(--ifm-breadcrumb-separator) center;content:" ";display:inline-block;filter:var(--ifm-breadcrumb-separator-filter);height:calc(var(--ifm-breadcrumb-separator-size)*var(--ifm-breadcrumb-size-multiplier)*var(--ifm-breadcrumb-separator-size-multiplier));margin:0 var(--ifm-breadcrumb-spacing);opacity:.5;width:calc(var(--ifm-breadcrumb-separator-size)*var(--ifm-breadcrumb-size-multiplier)*var(--ifm-breadcrumb-separator-size-multiplier))}.breadcrumbs__item--active .breadcrumbs__link{background:var(--ifm-breadcrumb-item-background-active);color:var(--ifm-breadcrumb-color-active)}.breadcrumbs__link{border-radius:var(--ifm-breadcrumb-border-radius);font-size:calc(1rem*var(--ifm-breadcrumb-size-multiplier));padding:calc(var(--ifm-breadcrumb-padding-vertical)*var(--ifm-breadcrumb-size-multiplier)) calc(var(--ifm-breadcrumb-padding-horizontal)*var(--ifm-breadcrumb-size-multiplier));transition-duration:var(--ifm-transition-fast);transition-property:background,color}.breadcrumbs__link:any-link:hover,.breadcrumbs__link:link:hover,.breadcrumbs__link:visited:hover,area[href].breadcrumbs__link:hover{background:var(--ifm-breadcrumb-item-background-active);text-decoration:none}.breadcrumbs--sm{--ifm-breadcrumb-size-multiplier:0.8}.breadcrumbs--lg{--ifm-breadcrumb-size-multiplier:1.2}.button{background-color:var(--ifm-button-background-color);border:var(--ifm-button-border-width) solid var(--ifm-button-border-color);border-radius:var(--ifm-button-border-radius);cursor:pointer;font-size:calc(.875rem*var(--ifm-button-size-multiplier));font-weight:var(--ifm-button-font-weight);line-height:1.5;padding:calc(var(--ifm-button-padding-vertical)*var(--ifm-button-size-multiplier)) calc(var(--ifm-button-padding-horizontal)*var(--ifm-button-size-multiplier));text-align:center;transition-duration:var(--ifm-button-transition-duration);transition-property:color,background,border-color;-webkit-user-select:none;user-select:none;white-space:nowrap}.button,.button:hover{color:var(--ifm-button-color)}.button--outline{--ifm-button-color:var(--ifm-button-border-color)}.button--outline:hover{--ifm-button-background-color:var(--ifm-button-border-color)}.button--link{--ifm-button-border-color:#0000;color:var(--ifm-link-color);text-decoration:var(--ifm-link-decoration)}.button--link.button--active,.button--link:active,.button--link:hover{color:var(--ifm-link-hover-color);text-decoration:var(--ifm-link-hover-decoration)}.button.disabled,.button:disabled,.button[disabled]{opacity:.65;pointer-events:none}.button--sm{--ifm-button-size-multiplier:0.8}.button--lg{--ifm-button-size-multiplier:1.35}.button--block{display:block;width:100%}.button.button--secondary{color:var(--ifm-color-gray-900)}:where(.button--primary){--ifm-button-background-color:var(--ifm-color-primary);--ifm-button-border-color:var(--ifm-color-primary)}:where(.button--primary):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-primary-dark);--ifm-button-border-color:var(--ifm-color-primary-dark)}.button--primary.button--active,.button--primary:active{--ifm-button-background-color:var(--ifm-color-primary-darker);--ifm-button-border-color:var(--ifm-color-primary-darker)}:where(.button--secondary){--ifm-button-background-color:var(--ifm-color-secondary);--ifm-button-border-color:var(--ifm-color-secondary)}:where(.button--secondary):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-secondary-dark);--ifm-button-border-color:var(--ifm-color-secondary-dark)}.button--secondary.button--active,.button--secondary:active{--ifm-button-background-color:var(--ifm-color-secondary-darker);--ifm-button-border-color:var(--ifm-color-secondary-darker)}:where(.button--success){--ifm-button-background-color:var(--ifm-color-success);--ifm-button-border-color:var(--ifm-color-success)}:where(.button--success):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-success-dark);--ifm-button-border-color:var(--ifm-color-success-dark)}.button--success.button--active,.button--success:active{--ifm-button-background-color:var(--ifm-color-success-darker);--ifm-button-border-color:var(--ifm-color-success-darker)}:where(.button--info){--ifm-button-background-color:var(--ifm-color-info);--ifm-button-border-color:var(--ifm-color-info)}:where(.button--info):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-info-dark);--ifm-button-border-color:var(--ifm-color-info-dark)}.button--info.button--active,.button--info:active{--ifm-button-background-color:var(--ifm-color-info-darker);--ifm-button-border-color:var(--ifm-color-info-darker)}:where(.button--warning){--ifm-button-background-color:var(--ifm-color-warning);--ifm-button-border-color:var(--ifm-color-warning)}:where(.button--warning):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-warning-dark);--ifm-button-border-color:var(--ifm-color-warning-dark)}.button--warning.button--active,.button--warning:active{--ifm-button-background-color:var(--ifm-color-warning-darker);--ifm-button-border-color:var(--ifm-color-warning-darker)}:where(.button--danger){--ifm-button-background-color:var(--ifm-color-danger);--ifm-button-border-color:var(--ifm-color-danger)}:where(.button--danger):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-danger-dark);--ifm-button-border-color:var(--ifm-color-danger-dark)}.button--danger.button--active,.button--danger:active{--ifm-button-background-color:var(--ifm-color-danger-darker);--ifm-button-border-color:var(--ifm-color-danger-darker)}.button-group{display:inline-flex;gap:var(--ifm-button-group-spacing)}.button-group>.button:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.button-group>.button:not(:last-child){border-bottom-right-radius:0;border-top-right-radius:0}.button-group--block{display:flex;justify-content:stretch}.button-group--block>.button{flex-grow:1}.card{background-color:var(--ifm-card-background-color);border-radius:var(--ifm-card-border-radius);box-shadow:var(--ifm-global-shadow-lw);display:flex;flex-direction:column;overflow:hidden}.card__image{padding-top:var(--ifm-card-vertical-spacing)}.card__image:first-child{padding-top:0}.card__body,.card__footer,.card__header{padding:var(--ifm-card-vertical-spacing) var(--ifm-card-horizontal-spacing)}.card__body:not(:last-child),.card__footer:not(:last-child),.card__header:not(:last-child){padding-bottom:0}.card__body>:last-child,.card__footer>:last-child,.card__header>:last-child{margin-bottom:0}.card__footer{margin-top:auto}.table-of-contents{font-size:.8rem;margin-bottom:0;padding:var(--ifm-toc-padding-vertical) 0}.table-of-contents,.table-of-contents ul{list-style:none;padding-left:var(--ifm-toc-padding-horizontal)}.table-of-contents li{margin:var(--ifm-toc-padding-vertical) var(--ifm-toc-padding-horizontal)}.table-of-contents__left-border{border-left:1px solid var(--ifm-toc-border-color)}.table-of-contents__link{color:var(--ifm-toc-link-color);display:block}.table-of-contents__link--active,.table-of-contents__link--active code,.table-of-contents__link:hover,.table-of-contents__link:hover code{color:var(--ifm-color-primary);text-decoration:none}.close{color:var(--ifm-color-black);float:right;font-size:1.5rem;font-weight:var(--ifm-font-weight-bold);line-height:1;opacity:.5;padding:1rem;transition:opacity var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.close:hover{opacity:.7}.close:focus,.theme-code-block-highlighted-line .codeLineNumber_Tfdd:before{opacity:.8}.dropdown{display:inline-flex;font-weight:var(--ifm-dropdown-font-weight);position:relative;vertical-align:top}.dropdown--hoverable:hover .dropdown__menu,.dropdown--show .dropdown__menu{opacity:1;pointer-events:all;transform:translateY(-1px);visibility:visible}#nprogress,.dropdown__menu,.navbar__item.dropdown .navbar__link:not([href]){pointer-events:none}.dropdown--right .dropdown__menu{left:inherit;right:0}.dropdown--nocaret .navbar__link:after{content:none!important}.dropdown__menu{background-color:var(--ifm-dropdown-background-color);border-radius:var(--ifm-global-radius);box-shadow:var(--ifm-global-shadow-md);left:0;max-height:80vh;min-width:10rem;opacity:0;overflow-y:auto;padding:.5rem;position:absolute;top:calc(100% - var(--ifm-navbar-item-padding-vertical) + .3rem);transform:translateY(-.625rem);transition-duration:var(--ifm-transition-fast);transition-property:opacity,transform,visibility;transition-timing-function:var(--ifm-transition-timing-default);visibility:hidden;z-index:var(--ifm-z-index-dropdown)}.sidebar_re4s,.tableOfContents_bqdL{max-height:calc(100vh - var(--ifm-navbar-height) - 2rem);overflow-y:auto}.menu__caret,.menu__link,.menu__list-item-collapsible{border-radius:.25rem;transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.dropdown__link{border-radius:.25rem;color:var(--ifm-dropdown-link-color);display:block;font-size:.875rem;margin-top:.2rem;padding:.25rem .5rem;white-space:nowrap}.dropdown__link--active,.dropdown__link:hover{background-color:var(--ifm-dropdown-hover-background-color);color:var(--ifm-dropdown-link-color);text-decoration:none}.dropdown__link--active,.dropdown__link--active:hover{--ifm-dropdown-link-color:var(--ifm-link-color)}.dropdown>.navbar__link:after{border-color:currentcolor #0000;border-style:solid;border-width:.4em .4em 0;content:"";margin-left:.3em;position:relative;top:2px;transform:translateY(-50%)}.footer{background-color:var(--ifm-footer-background-color);color:var(--ifm-footer-color);padding:var(--ifm-footer-padding-vertical) var(--ifm-footer-padding-horizontal)}.footer--dark{--ifm-footer-background-color:#303846;--ifm-footer-color:var(--ifm-footer-link-color);--ifm-footer-link-color:var(--ifm-color-secondary);--ifm-footer-title-color:var(--ifm-color-white)}.footer__links{margin-bottom:1rem}.footer__link-item{color:var(--ifm-footer-link-color);line-height:2}.footer__link-item:hover{color:var(--ifm-footer-link-hover-color)}.footer__link-separator{margin:0 var(--ifm-footer-link-horizontal-spacing)}.footer__logo{margin-top:1rem;max-width:var(--ifm-footer-logo-max-width)}.footer__title{color:var(--ifm-footer-title-color);font:700 var(--ifm-h4-font-size)/var(--ifm-heading-line-height) var(--ifm-font-family-base);margin-bottom:var(--ifm-heading-margin-bottom)}.menu,.navbar__link{font-weight:var(--ifm-font-weight-semibold)}.docItemContainer_Djhp article>:first-child,.docItemContainer_Djhp header+*,.footer__item{margin-top:0}.admonitionContent_S0QG>:last-child,.collapsibleContent_i85q>:last-child,.footer__items{margin-bottom:0}.codeBlockStandalone_MEMb,[type=checkbox]{padding:0}.hero{align-items:center;background-color:var(--ifm-hero-background-color);color:var(--ifm-hero-text-color);display:flex;padding:4rem 2rem}.hero--primary{--ifm-hero-background-color:var(--ifm-color-primary);--ifm-hero-text-color:var(--ifm-font-color-base-inverse)}.hero--dark{--ifm-hero-background-color:#303846;--ifm-hero-text-color:var(--ifm-color-white)}.hero__title,.title_f1Hy{font-size:3rem}.hero__subtitle{font-size:1.5rem}.menu__list{margin:0;padding-left:0}.menu__caret,.menu__link{padding:var(--ifm-menu-link-padding-vertical) var(--ifm-menu-link-padding-horizontal)}.menu__list .menu__list{flex:0 0 100%;margin-top:.25rem;padding-left:var(--ifm-menu-link-padding-horizontal)}.menu__list-item:not(:first-child){margin-top:.25rem}.menu__list-item--collapsed .menu__list{height:0;overflow:hidden}.details_lb9f[data-collapsed=false].isBrowser_bmU9>summary:before,.details_lb9f[open]:not(.isBrowser_bmU9)>summary:before,.menu__list-item--collapsed .menu__caret:before,.menu__list-item--collapsed .menu__link--sublist:after{transform:rotate(90deg)}.menu__list-item-collapsible{display:flex;flex-wrap:wrap;position:relative}.menu__caret:hover,.menu__link:hover,.menu__list-item-collapsible--active,.menu__list-item-collapsible:hover{background:var(--ifm-menu-color-background-hover)}.menu__list-item-collapsible .menu__link--active,.menu__list-item-collapsible .menu__link:hover{background:none!important}.menu__caret,.menu__link{align-items:center;display:flex}.menu__link{color:var(--ifm-menu-color);flex:1;line-height:1.25}.menu__link:hover{color:var(--ifm-menu-color);text-decoration:none}.menu__caret:before,.menu__link--sublist-caret:after{content:"";height:1.25rem;transform:rotate(180deg);transition:transform var(--ifm-transition-fast) linear;width:1.25rem;filter:var(--ifm-menu-link-sublist-icon-filter)}.menu__link--sublist-caret:after{background:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem;margin-left:auto;min-width:1.25rem}.menu__link--active,.menu__link--active:hover{color:var(--ifm-menu-color-active)}.navbar__brand,.navbar__link{color:var(--ifm-navbar-link-color)}.menu__link--active:not(.menu__link--sublist){background-color:var(--ifm-menu-color-background-active)}.menu__caret:before{background:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem}.navbar--dark,html[data-theme=dark]{--ifm-menu-link-sublist-icon-filter:invert(100%) sepia(94%) saturate(17%) hue-rotate(223deg) brightness(104%) contrast(98%)}.navbar{background-color:var(--ifm-navbar-background-color);box-shadow:var(--ifm-navbar-shadow);height:var(--ifm-navbar-height);padding:var(--ifm-navbar-padding-vertical) var(--ifm-navbar-padding-horizontal)}.navbar,.navbar>.container,.navbar>.container-fluid{display:flex}.navbar--fixed-top{position:sticky;top:0;z-index:var(--ifm-z-index-fixed)}.navbar-sidebar,.navbar-sidebar__backdrop{bottom:0;opacity:0;position:fixed;transition-duration:var(--ifm-transition-fast);transition-timing-function:ease-in-out;left:0;top:0;visibility:hidden}.navbar__inner{display:flex;flex-wrap:wrap;justify-content:space-between;width:100%}.navbar__brand{align-items:center;display:flex;margin-right:1rem;min-width:0}.navbar__brand:hover{color:var(--ifm-navbar-link-hover-color);text-decoration:none}.announcementBarContent_xLdY,.navbar__title{flex:1 1 auto}.navbar__toggle{display:none;margin-right:.5rem}.navbar__logo{flex:0 0 auto;height:2rem;margin-right:.5rem}.navbar__items{align-items:center;display:flex;flex:1;min-width:0}.navbar__items--center{flex:0 0 auto}.navbar__items--center .navbar__brand{margin:0}.navbar__items--center+.navbar__items--right{flex:1}.navbar__items--right{flex:0 0 auto;justify-content:flex-end}.navbar__items--right>:last-child{padding-right:0}.navbar__item{display:inline-block;padding:var(--ifm-navbar-item-padding-vertical) var(--ifm-navbar-item-padding-horizontal)}.navbar__link--active,.navbar__link:hover{color:var(--ifm-navbar-link-hover-color);text-decoration:none}.navbar--dark,.navbar--primary{--ifm-menu-color:var(--ifm-color-gray-300);--ifm-navbar-link-color:var(--ifm-color-gray-100);--ifm-navbar-search-input-background-color:#ffffff1a;--ifm-navbar-search-input-placeholder-color:#ffffff80;color:var(--ifm-color-white)}.navbar--dark{--ifm-navbar-background-color:#242526;--ifm-menu-color-background-active:#ffffff0d;--ifm-navbar-search-input-color:var(--ifm-color-white)}.navbar--primary{--ifm-navbar-background-color:var(--ifm-color-primary);--ifm-navbar-link-hover-color:var(--ifm-color-white);--ifm-menu-color-active:var(--ifm-color-white);--ifm-navbar-search-input-color:var(--ifm-color-emphasis-500)}.navbar__search-input{appearance:none;background:var(--ifm-navbar-search-input-background-color) var(--ifm-navbar-search-input-icon) no-repeat .75rem center/1rem 1rem;border:none;border-radius:2rem;color:var(--ifm-navbar-search-input-color);cursor:text;display:inline-block;font-size:.9rem;height:2rem;padding:0 .5rem 0 2.25rem;width:12.5rem}.navbar__search-input::placeholder{color:var(--ifm-navbar-search-input-placeholder-color)}.navbar-sidebar{background-color:var(--ifm-navbar-background-color);box-shadow:var(--ifm-global-shadow-md);transform:translate3d(-100%,0,0);transition-property:opacity,visibility,transform;width:var(--ifm-navbar-sidebar-width)}.navbar-sidebar--show .navbar-sidebar,.navbar-sidebar__items{transform:translateZ(0)}.navbar-sidebar--show .navbar-sidebar,.navbar-sidebar--show .navbar-sidebar__backdrop{opacity:1;visibility:visible}.navbar-sidebar__backdrop{background-color:#0009;right:0;transition-property:opacity,visibility}.navbar-sidebar__brand{align-items:center;box-shadow:var(--ifm-navbar-shadow);display:flex;flex:1;height:var(--ifm-navbar-height);padding:var(--ifm-navbar-padding-vertical) var(--ifm-navbar-padding-horizontal)}.navbar-sidebar__items{display:flex;height:calc(100% - var(--ifm-navbar-height));transition:transform var(--ifm-transition-fast) ease-in-out}.navbar-sidebar__items--show-secondary{transform:translate3d(calc((var(--ifm-navbar-sidebar-width))*-1),0,0)}.navbar-sidebar__item{flex-shrink:0;padding:.5rem;width:calc(var(--ifm-navbar-sidebar-width))}.navbar-sidebar__back{background:var(--ifm-menu-color-background-active);font-size:15px;font-weight:var(--ifm-button-font-weight);margin:0 0 .2rem -.5rem;padding:.6rem 1.5rem;position:relative;text-align:left;top:-.5rem;width:calc(100% + 1rem)}.navbar-sidebar__close{display:flex;margin-left:auto}.pagination{column-gap:var(--ifm-pagination-page-spacing);display:flex;font-size:var(--ifm-pagination-font-size);padding-left:0}.pagination--sm{--ifm-pagination-font-size:0.8rem;--ifm-pagination-padding-horizontal:0.8rem;--ifm-pagination-padding-vertical:0.2rem}.pagination--lg{--ifm-pagination-font-size:1.2rem;--ifm-pagination-padding-horizontal:1.2rem;--ifm-pagination-padding-vertical:0.3rem}.pagination__item{display:inline-flex}.pagination__item>span{padding:var(--ifm-pagination-padding-vertical)}.pagination__item--active .pagination__link{color:var(--ifm-pagination-color-active)}.pagination__item--active .pagination__link,.pagination__item:not(.pagination__item--active):hover .pagination__link{background:var(--ifm-pagination-item-active-background)}.pagination__item--disabled,.pagination__item[disabled]{opacity:.25;pointer-events:none}.pagination__link{border-radius:var(--ifm-pagination-border-radius);color:var(--ifm-font-color-base);display:inline-block;padding:var(--ifm-pagination-padding-vertical) var(--ifm-pagination-padding-horizontal);transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.pagination__link:hover,.sidebarItemLink_mo7H:hover{text-decoration:none}.pagination-nav{grid-gap:var(--ifm-spacing-horizontal);display:grid;gap:var(--ifm-spacing-horizontal);grid-template-columns:repeat(2,1fr)}.pagination-nav__link{border:1px solid var(--ifm-color-emphasis-300);border-radius:var(--ifm-pagination-nav-border-radius);display:block;height:100%;line-height:var(--ifm-heading-line-height);padding:var(--ifm-global-spacing);transition:border-color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.pagination-nav__link:hover{border-color:var(--ifm-pagination-nav-color-hover);text-decoration:none}.pagination-nav__link--next{grid-column:2/3;text-align:right}.pagination-nav__label{font-size:var(--ifm-h4-font-size);font-weight:var(--ifm-heading-font-weight);word-break:break-word}.pagination-nav__link--prev .pagination-nav__label:before{content:"« "}.pagination-nav__link--next .pagination-nav__label:after{content:" »"}.pagination-nav__sublabel{color:var(--ifm-color-content-secondary);font-size:var(--ifm-h5-font-size);font-weight:var(--ifm-font-weight-semibold);margin-bottom:.25rem}.pills__item,.sidebarItemTitle_pO2u,.tabs{font-weight:var(--ifm-font-weight-bold)}.pills{display:flex;gap:var(--ifm-pills-spacing);padding-left:0}.pills__item{border-radius:.5rem;cursor:pointer;display:inline-block;padding:.25rem 1rem;transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.tabs,:not(.containsTaskList_mC6p>li)>.containsTaskList_mC6p{padding-left:0}.pills__item--active{color:var(--ifm-pills-color-active)}.pills__item--active,.pills__item:not(.pills__item--active):hover{background:var(--ifm-pills-color-background-active)}.pills--block{justify-content:stretch}.pills--block .pills__item{flex-grow:1;text-align:center}.tabs{color:var(--ifm-tabs-color);display:flex;margin-bottom:0;overflow-x:auto}.tabs__item{border-bottom:3px solid #0000;border-radius:var(--ifm-global-radius);cursor:pointer;display:inline-flex;padding:var(--ifm-tabs-padding-vertical) var(--ifm-tabs-padding-horizontal);transition:background-color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.tabs__item--active{border-bottom-color:var(--ifm-tabs-color-active-border);border-bottom-left-radius:0;border-bottom-right-radius:0;color:var(--ifm-tabs-color-active)}.tabs__item:hover{background-color:var(--ifm-hover-overlay)}.tabs--block{justify-content:stretch}.tabs--block .tabs__item{flex-grow:1;justify-content:center}html[data-theme=dark]{--ifm-color-scheme:dark;--ifm-color-emphasis-0:var(--ifm-color-gray-1000);--ifm-color-emphasis-100:var(--ifm-color-gray-900);--ifm-color-emphasis-200:var(--ifm-color-gray-800);--ifm-color-emphasis-300:var(--ifm-color-gray-700);--ifm-color-emphasis-400:var(--ifm-color-gray-600);--ifm-color-emphasis-600:var(--ifm-color-gray-400);--ifm-color-emphasis-700:var(--ifm-color-gray-300);--ifm-color-emphasis-800:var(--ifm-color-gray-200);--ifm-color-emphasis-900:var(--ifm-color-gray-100);--ifm-color-emphasis-1000:var(--ifm-color-gray-0);--ifm-background-color:#1b1b1d;--ifm-background-surface-color:#242526;--ifm-hover-overlay:#ffffff0d;--ifm-color-content:#e3e3e3;--ifm-color-content-secondary:#fff;--ifm-breadcrumb-separator-filter:invert(64%) sepia(11%) saturate(0%) hue-rotate(149deg) brightness(99%) contrast(95%);--ifm-code-background:#ffffff1a;--ifm-scrollbar-track-background-color:#444;--ifm-scrollbar-thumb-background-color:#686868;--ifm-scrollbar-thumb-hover-background-color:#7a7a7a;--ifm-table-stripe-background:#ffffff12;--ifm-toc-border-color:var(--ifm-color-emphasis-200);--ifm-color-primary-contrast-background:#102445;--ifm-color-primary-contrast-foreground:#ebf2fc;--ifm-color-secondary-contrast-background:#474748;--ifm-color-secondary-contrast-foreground:#fdfdfe;--ifm-color-success-contrast-background:#003100;--ifm-color-success-contrast-foreground:#e6f6e6;--ifm-color-info-contrast-background:#193c47;--ifm-color-info-contrast-foreground:#eef9fd;--ifm-color-warning-contrast-background:#4d3800;--ifm-color-warning-contrast-foreground:#fff8e6;--ifm-color-danger-contrast-background:#4b1113;--ifm-color-danger-contrast-foreground:#ffebec}#nprogress .bar{background:var(--docusaurus-progress-bar-color);height:2px;left:0;position:fixed;top:0;width:100%;z-index:1031}#nprogress .peg{box-shadow:0 0 10px var(--docusaurus-progress-bar-color),0 0 5px var(--docusaurus-progress-bar-color);height:100%;opacity:1;position:absolute;right:0;transform:rotate(3deg) translateY(-4px);width:100px}body,h2,h3,h4,h5,h6{font-family:Fira Sans,-apple-system,sans-serif}.navbar__brand b,h1{font-family:Alfa Slab One,serif;font-weight:300}article h1{padding:25px 30px 0 5px;width:100%}h2{font-weight:600}h3,h4,h5,h6{font-weight:500}.navbar__brand b{font-size:30px}footer.footer--dark{background-color:#2a3439}.skipToContent_fXgn{background-color:var(--ifm-background-surface-color);color:var(--ifm-color-emphasis-900);left:100%;padding:calc(var(--ifm-global-spacing)/2) var(--ifm-global-spacing);position:fixed;top:1rem;z-index:calc(var(--ifm-z-index-fixed) + 1)}.skipToContent_fXgn:focus{box-shadow:var(--ifm-global-shadow-md);left:1rem}.closeButton_CVFx{line-height:0;padding:0}.content_knG7{font-size:85%;padding:5px 0;text-align:center}.content_knG7 a{color:inherit;text-decoration:underline}.announcementBar_mb4j{align-items:center;background-color:var(--ifm-color-white);border-bottom:1px solid var(--ifm-color-emphasis-100);color:var(--ifm-color-black);display:flex;height:var(--docusaurus-announcement-bar-height)}#__docusaurus-base-url-issue-banner-container,.docSidebarContainer_b6E3,.sidebarLogo_isFc,.themedImage_ToTc,[data-theme=dark] .lightToggleIcon_pyhR,[data-theme=light] .darkToggleIcon_wfgR,html[data-announcement-bar-initially-dismissed=true] .announcementBar_mb4j{display:none}.announcementBarPlaceholder_vyr4{flex:0 0 10px}.announcementBarClose_gvF7{align-self:stretch;flex:0 0 30px}.toggle_vylO{height:2rem;width:2rem}.toggleButton_gllP{align-items:center;border-radius:50%;display:flex;height:100%;justify-content:center;transition:background var(--ifm-transition-fast);width:100%}.toggleButton_gllP:hover{background:var(--ifm-color-emphasis-200)}.toggleButtonDisabled_aARS{cursor:not-allowed}.darkNavbarColorModeToggle_X3D1:hover{background:var(--ifm-color-gray-800)}[data-theme=dark] .themedImage--dark_i4oU,[data-theme=light] .themedImage--light_HNdA,html:not([data-theme]) .themedComponent--light_NU7w{display:initial}.iconExternalLink_nPIU{margin-left:.3rem}.iconLanguage_nlXk{margin-right:5px;vertical-align:text-bottom}.navbarHideable_m1mJ{transition:transform var(--ifm-transition-fast) ease}.navbarHidden_jGov{transform:translate3d(0,calc(-100% - 2px),0)}.errorBoundaryError_a6uf{color:red;white-space:pre-wrap}body:not(.navigation-with-keyboard) :not(input):focus{outline:0}.footerLogoLink_BH7S{opacity:.5;transition:opacity var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.footerLogoLink_BH7S:hover,.hash-link:focus,:hover>.hash-link{opacity:1}.mainWrapper_z2l0{display:flex;flex:1 0 auto;flex-direction:column}.docusaurus-mt-lg{margin-top:3rem}#__docusaurus{display:flex;flex-direction:column;min-height:100%}.sidebar_re4s{position:sticky;top:calc(var(--ifm-navbar-height) + 2rem)}.sidebarItemTitle_pO2u{font-size:var(--ifm-h3-font-size)}.container_mt6G,.sidebarItemList_Yudw{font-size:.9rem}.sidebarItem__DBe{margin-top:.7rem}.sidebarItemLink_mo7H{color:var(--ifm-font-color-base);display:block}.sidebarItemLinkActive_I1ZP{color:var(--ifm-color-primary)!important}.backToTopButton_sjWU{background-color:var(--ifm-color-emphasis-200);border-radius:50%;bottom:1.3rem;box-shadow:var(--ifm-global-shadow-lw);height:3rem;opacity:0;position:fixed;right:1.3rem;transform:scale(0);transition:all var(--ifm-transition-fast) var(--ifm-transition-timing-default);visibility:hidden;width:3rem;z-index:calc(var(--ifm-z-index-fixed) - 1)}.buttonGroup__atx button,.codeBlockContainer_Ckt0{background:var(--prism-background-color);color:var(--prism-color)}.backToTopButton_sjWU:after{background-color:var(--ifm-color-emphasis-1000);content:" ";display:inline-block;height:100%;-webkit-mask:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem no-repeat;mask:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem no-repeat;width:100%}.backToTopButtonShow_xfvO{opacity:1;transform:scale(1);visibility:visible}[data-theme=dark]:root{--docusaurus-collapse-button-bg:#ffffff0d;--docusaurus-collapse-button-bg-hover:#ffffff1a}.collapseSidebarButton_PEFL{display:none;margin:0}.docMainContainer_gTbr,.docPage__5DB{display:flex;width:100%}.docPage__5DB{flex:1 0}.docsWrapper_BCFX{display:flex;flex:1 0 auto}.authorCol_Hf19{flex-grow:1!important;max-width:inherit!important}.imageOnlyAuthorRow_pa_O{display:flex;flex-flow:row wrap}.imageOnlyAuthorCol_G86a{margin-left:.3rem;margin-right:.3rem}.codeBlockContainer_Ckt0{border-radius:var(--ifm-code-border-radius);box-shadow:var(--ifm-global-shadow-lw);margin-bottom:var(--ifm-leading)}.codeBlockContent_biex{border-radius:inherit;direction:ltr;position:relative}.codeBlockTitle_Ktv7{border-bottom:1px solid var(--ifm-color-emphasis-300);border-top-left-radius:inherit;border-top-right-radius:inherit;font-size:var(--ifm-code-font-size);font-weight:500;padding:.75rem var(--ifm-pre-padding)}.codeBlock_bY9V{--ifm-pre-background:var(--prism-background-color);margin:0;padding:0}.codeBlockTitle_Ktv7+.codeBlockContent_biex .codeBlock_bY9V{border-top-left-radius:0;border-top-right-radius:0}.codeBlockLines_e6Vv{float:left;font:inherit;min-width:100%;padding:var(--ifm-pre-padding)}.codeBlockLinesWithNumbering_o6Pm{display:table;padding:var(--ifm-pre-padding) 0}.buttonGroup__atx{column-gap:.2rem;display:flex;position:absolute;right:calc(var(--ifm-pre-padding)/2);top:calc(var(--ifm-pre-padding)/2)}.buttonGroup__atx button{align-items:center;border:1px solid var(--ifm-color-emphasis-300);border-radius:var(--ifm-global-radius);display:flex;line-height:0;opacity:0;padding:.4rem;transition:opacity var(--ifm-transition-fast) ease-in-out}.buttonGroup__atx button:focus-visible,.buttonGroup__atx button:hover{opacity:1!important}.theme-code-block:hover .buttonGroup__atx button{opacity:.4}.iconEdit_Z9Sw{margin-right:.3em;vertical-align:sub}:where(:root){--docusaurus-highlighted-code-line-bg:#484d5b}:where([data-theme=dark]){--docusaurus-highlighted-code-line-bg:#646464}.theme-code-block-highlighted-line{background-color:var(--docusaurus-highlighted-code-line-bg);display:block;margin:0 calc(var(--ifm-pre-padding)*-1);padding:0 var(--ifm-pre-padding)}.codeLine_lJS_{counter-increment:a;display:table-row}.codeLineNumber_Tfdd{background:var(--ifm-pre-background);display:table-cell;left:0;overflow-wrap:normal;padding:0 var(--ifm-pre-padding);position:sticky;text-align:right;width:1%}.codeLineNumber_Tfdd:before{content:counter(a);opacity:.4}.codeLineContent_feaV{padding-right:var(--ifm-pre-padding)}.tag_zVej{border:1px solid var(--docusaurus-tag-list-border);transition:border var(--ifm-transition-fast)}.tag_zVej:hover{--docusaurus-tag-list-border:var(--ifm-link-color);text-decoration:none}.tagRegular_sFm0{border-radius:var(--ifm-global-radius);font-size:90%;padding:.2rem .5rem .3rem}.tagWithCount_h2kH{align-items:center;border-left:0;display:flex;padding:0 .5rem 0 1rem;position:relative}.tagWithCount_h2kH:after,.tagWithCount_h2kH:before{border:1px solid var(--docusaurus-tag-list-border);content:"";position:absolute;top:50%;transition:inherit}.tagWithCount_h2kH:before{border-bottom:0;border-right:0;height:1.18rem;right:100%;transform:translate(50%,-50%) rotate(-45deg);width:1.18rem}.tagWithCount_h2kH:after{border-radius:50%;height:.5rem;left:0;transform:translateY(-50%);width:.5rem}.tagWithCount_h2kH span{background:var(--ifm-color-secondary);border-radius:var(--ifm-global-radius);color:var(--ifm-color-black);font-size:.7rem;line-height:1.2;margin-left:.3rem;padding:.1rem .4rem}.tag_Nnez{display:inline-block;margin:.5rem .5rem 0 1rem}.theme-code-block:hover .copyButtonCopied_obH4{opacity:1!important}.copyButtonIcons_eSgA{height:1.125rem;position:relative;width:1.125rem}.copyButtonIcon_y97N,.copyButtonSuccessIcon_LjdS{fill:currentColor;height:inherit;left:0;opacity:inherit;position:absolute;top:0;transition:all var(--ifm-transition-fast) ease;width:inherit}.copyButtonSuccessIcon_LjdS{color:#00d600;left:50%;opacity:0;top:50%;transform:translate(-50%,-50%) scale(.33)}.copyButtonCopied_obH4 .copyButtonIcon_y97N{opacity:0;transform:scale(.33)}.copyButtonCopied_obH4 .copyButtonSuccessIcon_LjdS{opacity:1;transform:translate(-50%,-50%) scale(1);transition-delay:75ms}.tags_jXut{display:inline}.tag_QGVx{display:inline-block;margin:0 .4rem .5rem 0}.lastUpdated_vwxv{font-size:smaller;font-style:italic;margin-top:.2rem}.tocCollapsibleButton_TO0P{align-items:center;display:flex;font-size:inherit;justify-content:space-between;padding:.4rem .8rem;width:100%}.tocCollapsibleButton_TO0P:after{background:var(--ifm-menu-link-sublist-icon) 50% 50%/2rem 2rem no-repeat;content:"";filter:var(--ifm-menu-link-sublist-icon-filter);height:1.25rem;transform:rotate(180deg);transition:transform var(--ifm-transition-fast);width:1.25rem}.tocCollapsibleButtonExpanded_MG3E:after,.tocCollapsibleExpanded_sAul{transform:none}.tocCollapsible_ETCw{background-color:var(--ifm-menu-color-background-active);border-radius:var(--ifm-global-radius);margin:1rem 0}.tocCollapsibleContent_vkbj>ul{border-left:none;border-top:1px solid var(--ifm-color-emphasis-300);font-size:15px;padding:.2rem 0}.tocCollapsibleContent_vkbj ul li{margin:.4rem .8rem}.tocCollapsibleContent_vkbj a{display:block}.wordWrapButtonIcon_Bwma{height:1.2rem;width:1.2rem}.details_lb9f{--docusaurus-details-summary-arrow-size:0.38rem;--docusaurus-details-transition:transform 200ms ease;--docusaurus-details-decoration-color:grey}.details_lb9f>summary{cursor:pointer;padding-left:1rem;position:relative}.details_lb9f>summary::-webkit-details-marker{display:none}.details_lb9f>summary:before{border-color:#0000 #0000 #0000 var(--docusaurus-details-decoration-color);border-style:solid;border-width:var(--docusaurus-details-summary-arrow-size);content:"";left:0;position:absolute;top:.45rem;transform:rotate(0);transform-origin:calc(var(--docusaurus-details-summary-arrow-size)/2) 50%;transition:var(--docusaurus-details-transition)}.collapsibleContent_i85q{border-top:1px solid var(--docusaurus-details-decoration-color);margin-top:1rem;padding-top:1rem}.details_b_Ee{--docusaurus-details-decoration-color:var(--ifm-alert-border-color);--docusaurus-details-transition:transform var(--ifm-transition-fast) ease;border:1px solid var(--ifm-alert-border-color);margin:0 0 var(--ifm-spacing-vertical)}.anchorWithStickyNavbar_LWe7{scroll-margin-top:calc(var(--ifm-navbar-height) + .5rem)}.anchorWithHideOnScrollNavbar_WYt5{scroll-margin-top:.5rem}.hash-link{opacity:0;padding-left:.5rem;transition:opacity var(--ifm-transition-fast);-webkit-user-select:none;user-select:none}.hash-link:before{content:"#"}.img_ev3q{height:auto}.admonition_LlT9{margin-bottom:1em}.admonitionHeading_tbUL{font:var(--ifm-heading-font-weight) var(--ifm-h5-font-size)/var(--ifm-heading-line-height) var(--ifm-heading-font-family);margin-bottom:.3rem}.admonitionHeading_tbUL code{text-transform:none}.admonitionIcon_kALy{display:inline-block;margin-right:.4em;vertical-align:middle}.admonitionIcon_kALy svg{fill:var(--ifm-alert-foreground-color);display:inline-block;height:1.6em;width:1.6em}.blogPostFooterDetailsFull_mRVl{flex-direction:column}.tableOfContents_bqdL{position:sticky;top:calc(var(--ifm-navbar-height) + 1rem)}.breadcrumbHomeIcon_YNFT{height:1.1rem;position:relative;top:1px;vertical-align:top;width:1.1rem}.breadcrumbsContainer_Z_bl{--ifm-breadcrumb-size-multiplier:0.8;margin-bottom:.8rem}@media (min-width:997px){.collapseSidebarButton_PEFL,.expandButton_m80_{background-color:var(--docusaurus-collapse-button-bg)}:root{--docusaurus-announcement-bar-height:30px}.announcementBarClose_gvF7,.announcementBarPlaceholder_vyr4{flex-basis:50px}.searchBox_ZlJk{padding:var(--ifm-navbar-item-padding-vertical) var(--ifm-navbar-item-padding-horizontal)}.collapseSidebarButton_PEFL{border:1px solid var(--ifm-toc-border-color);border-radius:0;bottom:0;display:block!important;height:40px;position:sticky}.collapseSidebarButtonIcon_kv0_{margin-top:4px;transform:rotate(180deg)}.expandButtonIcon_BlDH,[dir=rtl] .collapseSidebarButtonIcon_kv0_{transform:rotate(0)}.collapseSidebarButton_PEFL:focus,.collapseSidebarButton_PEFL:hover,.expandButton_m80_:focus,.expandButton_m80_:hover{background-color:var(--docusaurus-collapse-button-bg-hover)}.menuHtmlItem_M9Kj{padding:var(--ifm-menu-link-padding-vertical) var(--ifm-menu-link-padding-horizontal)}.menu_SIkG{flex-grow:1;padding:.5rem}@supports (scrollbar-gutter:stable){.menu_SIkG{padding:.5rem 0 .5rem .5rem;scrollbar-gutter:stable}}.menuWithAnnouncementBar_GW3s{margin-bottom:var(--docusaurus-announcement-bar-height)}.sidebar_njMd{display:flex;flex-direction:column;height:100%;padding-top:var(--ifm-navbar-height);width:var(--doc-sidebar-width)}.sidebarWithHideableNavbar_wUlq{padding-top:0}.sidebarHidden_VK0M{opacity:0;visibility:hidden}.sidebarLogo_isFc{align-items:center;color:inherit!important;display:flex!important;margin:0 var(--ifm-navbar-padding-horizontal);max-height:var(--ifm-navbar-height);min-height:var(--ifm-navbar-height);text-decoration:none!important}.sidebarLogo_isFc img{height:2rem;margin-right:.5rem}.expandButton_m80_{align-items:center;display:flex;height:100%;justify-content:center;position:absolute;right:0;top:0;transition:background-color var(--ifm-transition-fast) ease;width:100%}[dir=rtl] .expandButtonIcon_BlDH{transform:rotate(180deg)}.docSidebarContainer_b6E3{border-right:1px solid var(--ifm-toc-border-color);clip-path:inset(0);display:block;margin-top:calc(var(--ifm-navbar-height)*-1);transition:width var(--ifm-transition-fast) ease;width:var(--doc-sidebar-width);will-change:width}.docSidebarContainerHidden_b3ry{cursor:pointer;width:var(--doc-sidebar-hidden-width)}.sidebarViewport_Xe31{height:100%;max-height:100vh;position:sticky;top:0}.docMainContainer_gTbr{flex-grow:1;max-width:calc(100% - var(--doc-sidebar-width))}.docMainContainerEnhanced_Uz_u{max-width:calc(100% - var(--doc-sidebar-hidden-width))}.docItemWrapperEnhanced_czyv{max-width:calc(var(--ifm-container-width) + var(--doc-sidebar-width))!important}.lastUpdated_vwxv{text-align:right}.tocMobile_ITEo{display:none}.docItemCol_VOVn{max-width:75%!important}}@media (min-width:1440px){.container{max-width:var(--ifm-container-width-xl)}}@media (max-width:996px){.col{--ifm-col-width:100%;flex-basis:var(--ifm-col-width);margin-left:0}.footer{--ifm-footer-padding-horizontal:0}.colorModeToggle_DEke,.footer__link-separator,.navbar__item,.sidebar_re4s,.tableOfContents_bqdL{display:none}.footer__col{margin-bottom:calc(var(--ifm-spacing-vertical)*3)}.footer__link-item{display:block}.hero{padding-left:0;padding-right:0}.navbar>.container,.navbar>.container-fluid{padding:0}.navbar__toggle{display:inherit}.navbar__search-input{width:9rem}.pills--block,.tabs--block{flex-direction:column}.searchBox_ZlJk{position:absolute;right:var(--ifm-navbar-padding-horizontal)}.docItemContainer_F8PC{padding:0 .3rem}}@media (max-width:576px){.markdown h1:first-child{--ifm-h1-font-size:2rem}.markdown>h2{--ifm-h2-font-size:1.5rem}.markdown>h3{--ifm-h3-font-size:1.25rem}.title_f1Hy{font-size:2rem}}@media (hover:hover){.backToTopButton_sjWU:hover{background-color:var(--ifm-color-emphasis-300)}}@media (pointer:fine){.thin-scrollbar{scrollbar-width:thin}.thin-scrollbar::-webkit-scrollbar{height:var(--ifm-scrollbar-size);width:var(--ifm-scrollbar-size)}.thin-scrollbar::-webkit-scrollbar-track{background:var(--ifm-scrollbar-track-background-color);border-radius:10px}.thin-scrollbar::-webkit-scrollbar-thumb{background:var(--ifm-scrollbar-thumb-background-color);border-radius:10px}.thin-scrollbar::-webkit-scrollbar-thumb:hover{background:var(--ifm-scrollbar-thumb-hover-background-color)}}@media (prefers-reduced-motion:reduce){:root{--ifm-transition-fast:0ms;--ifm-transition-slow:0ms}}@media print{.announcementBar_mb4j,.footer,.menu,.navbar,.pagination-nav,.table-of-contents,.tocMobile_ITEo{display:none}.tabs{page-break-inside:avoid}.codeBlockLines_e6Vv{white-space:pre-wrap}} \ No newline at end of file diff --git a/docs/0.16.0/assets/images/blog-test-driven-documentation-insert-7dfbb3a9123d4aa47b845b7dede97dc9.jpg b/docs/0.16.0/assets/images/blog-test-driven-documentation-insert-7dfbb3a9123d4aa47b845b7dede97dc9.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e2914690e40e7ce6670a4d1da42ac30067bcb901 GIT binary patch literal 363481 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�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 b<@`6K=zq4cfBF3XU1#f3{{MUO|1{n.d(t,{xA:()=>c,yg:()=>y});var r=n(6540);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),u=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},c=function(e){var t=u(e.components);return r.createElement(s.Provider,{value:t},e.children)},p="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},g=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,l=e.originalType,s=e.parentName,c=o(e,["components","mdxType","originalType","parentName"]),p=u(n),g=a,y=p["".concat(s,".").concat(g)]||p[g]||m[g]||l;return n?r.createElement(y,i(i({ref:t},c),{},{components:n})):r.createElement(y,i({ref:t},c))}));function y(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var l=n.length,i=new Array(l);i[0]=g;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[p]="string"==typeof e?e:a,i[1]=o;for(var u=2;u{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>m,frontMatter:()=>l,metadata:()=>o,toc:()=>u});var r=n(8168),a=(n(6540),n(5680));const l={},i="LTRIM",o={unversionedId:"sql-syntax/functions/text/ltrim",id:"sql-syntax/functions/text/ltrim",title:"LTRIM",description:"The LTRIM function in SQL removes characters from the left (leading side) of a string.",source:"@site/docs/sql-syntax/functions/text/ltrim.md",sourceDirName:"sql-syntax/functions/text",slug:"/sql-syntax/functions/text/ltrim",permalink:"/docs/0.16.0/sql-syntax/functions/text/ltrim",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"LPAD",permalink:"/docs/0.16.0/sql-syntax/functions/text/lpad"},next:{title:"POSITION",permalink:"/docs/0.16.0/sql-syntax/functions/text/position"}},s={},u=[{value:"Syntax",id:"syntax",level:2},{value:"Parameters",id:"parameters",level:2},{value:"Return Value",id:"return-value",level:2},{value:"Errors",id:"errors",level:2},{value:"Examples",id:"examples",level:2}],c={toc:u},p="wrapper";function m(e){let{components:t,...n}=e;return(0,a.yg)(p,(0,r.A)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"ltrim"},"LTRIM"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"LTRIM")," function in SQL removes characters from the left (leading side) of a string."),(0,a.yg)("h2",{id:"syntax"},"Syntax"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"LTRIM(string, trim_string)\n")),(0,a.yg)("h2",{id:"parameters"},"Parameters"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"string"),": The original string to trim."),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"trim_string")," (optional): The characters to remove from the string. If not supplied, spaces are removed.")),(0,a.yg)("h2",{id:"return-value"},"Return Value"),(0,a.yg)("p",null,"The function returns a new string that is the same as the original string, but without the specified leading characters."),(0,a.yg)("h2",{id:"errors"},"Errors"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},"If the ",(0,a.yg)("inlineCode",{parentName:"li"},"string")," or ",(0,a.yg)("inlineCode",{parentName:"li"},"trim_string")," argument is not a string, a ",(0,a.yg)("inlineCode",{parentName:"li"},"FunctionRequiresStringValue")," error will be returned.")),(0,a.yg)("h2",{id:"examples"},"Examples"),(0,a.yg)("p",null,"Consider a table ",(0,a.yg)("inlineCode",{parentName:"p"},"Item")," created and filled with the following data:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE Item (\n name TEXT\n);\nINSERT INTO Item VALUES (' zzzytest');\n")),(0,a.yg)("p",null,"You can use the ",(0,a.yg)("inlineCode",{parentName:"p"},"LTRIM")," function to remove leading spaces from the ",(0,a.yg)("inlineCode",{parentName:"p"},"name")," values:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT LTRIM(name) AS trimmed_name FROM Item;\n")),(0,a.yg)("p",null,"This will return:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre"},"zzzytest\n")),(0,a.yg)("p",null,"You can also specify a string of characters to remove. The function will remove any character in this string from the start of the original string:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT LTRIM(name, ' z') AS trimmed_name FROM Item;\n")),(0,a.yg)("p",null,"This will return:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre"},"ytest\n")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/017e736e.f5dc6055.js b/docs/0.16.0/assets/js/017e736e.f5dc6055.js new file mode 100644 index 00000000..e3e6bfb5 --- /dev/null +++ b/docs/0.16.0/assets/js/017e736e.f5dc6055.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[5183],{5680:(e,t,r)=>{r.d(t,{xA:()=>d,yg:()=>g});var a=r(6540);function i(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function n(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,a)}return r}function u(e){for(var t=1;t=0||(i[r]=e[r]);return i}(e,t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(i[r]=e[r])}return i}var l=a.createContext({}),o=function(e){var t=a.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):u(u({},t),e)),r},d=function(e){var t=o(e.components);return a.createElement(l.Provider,{value:t},e.children)},c="mdxType",y={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},p=a.forwardRef((function(e,t){var r=e.components,i=e.mdxType,n=e.originalType,l=e.parentName,d=s(e,["components","mdxType","originalType","parentName"]),c=o(r),p=i,g=c["".concat(l,".").concat(p)]||c[p]||y[p]||n;return r?a.createElement(g,u(u({ref:t},d),{},{components:r})):a.createElement(g,u({ref:t},d))}));function g(e,t){var r=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var n=r.length,u=new Array(n);u[0]=p;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[c]="string"==typeof e?e:i,u[1]=s;for(var o=2;o{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>u,default:()=>y,frontMatter:()=>n,metadata:()=>s,toc:()=>o});var a=r(8168),i=(r(6540),r(5680));const n={sidebar_position:3},u="Creating Derived Subqueries",s={unversionedId:"ast-builder/statements/querying/creating-derived-subqueries",id:"ast-builder/statements/querying/creating-derived-subqueries",title:"Creating Derived Subqueries",description:"This document covers the aliasas functionality of the AST Builder in the GlueSQL project. The aliasas method allows you to create a derived subquery, which is similar to subqueries in SQL. It gives you the ability to use the output of a query as a table to perform further queries.",source:"@site/docs/ast-builder/statements/querying/creating-derived-subqueries.md",sourceDirName:"ast-builder/statements/querying",slug:"/ast-builder/statements/querying/creating-derived-subqueries",permalink:"/docs/0.16.0/ast-builder/statements/querying/creating-derived-subqueries",draft:!1,tags:[],version:"current",sidebarPosition:3,frontMatter:{sidebar_position:3},sidebar:"autoSidebar",previous:{title:"Using Preloaded Data",permalink:"/docs/0.16.0/ast-builder/statements/querying/using-preloaded-data"},next:{title:"Data Aggregation",permalink:"/docs/0.16.0/ast-builder/statements/querying/data-aggregation"}},l={},o=[{value:"Basic Usage",id:"basic-usage",level:2},{value:"Examples",id:"examples",level:2},{value:"Derived Subquery with Filter",id:"derived-subquery-with-filter",level:3},{value:"Derived Subquery with Projection",id:"derived-subquery-with-projection",level:3},{value:"Derived Subquery with Join",id:"derived-subquery-with-join",level:3},{value:"Derived Subquery with Group By and Having",id:"derived-subquery-with-group-by-and-having",level:3},{value:"Derived Subquery with Order By",id:"derived-subquery-with-order-by",level:3},{value:"Derived Subquery with Offset and Limit",id:"derived-subquery-with-offset-and-limit",level:3}],d={toc:o},c="wrapper";function y(e){let{components:t,...r}=e;return(0,i.yg)(c,(0,a.A)({},d,r,{components:t,mdxType:"MDXLayout"}),(0,i.yg)("h1",{id:"creating-derived-subqueries"},"Creating Derived Subqueries"),(0,i.yg)("p",null,"This document covers the ",(0,i.yg)("inlineCode",{parentName:"p"},"alias_as")," functionality of the AST Builder in the GlueSQL project. The ",(0,i.yg)("inlineCode",{parentName:"p"},"alias_as")," method allows you to create a derived subquery, which is similar to subqueries in SQL. It gives you the ability to use the output of a query as a table to perform further queries."),(0,i.yg)("h2",{id:"basic-usage"},"Basic Usage"),(0,i.yg)("p",null,"To use the ",(0,i.yg)("inlineCode",{parentName:"p"},"alias_as")," method, simply chain it to the end of a query builder method before executing the query. The derived subquery can then be used for further queries. Here's an example:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Item")\n .select()\n .alias_as("Sub")\n .select()\n .execute(glue)\n .await;\n')),(0,i.yg)("p",null,"In this example, the ",(0,i.yg)("inlineCode",{parentName:"p"},"alias_as")," method is used after the ",(0,i.yg)("inlineCode",{parentName:"p"},"select"),' method, creating a derived subquery named "Sub" that can be used in subsequent queries.'),(0,i.yg)("h2",{id:"examples"},"Examples"),(0,i.yg)("p",null,"The following examples demonstrate how to use the ",(0,i.yg)("inlineCode",{parentName:"p"},"alias_as")," method with various query operations. "),(0,i.yg)("h3",{id:"derived-subquery-with-filter"},"Derived Subquery with Filter"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Item")\n .select()\n .filter("item_id = 300")\n .alias_as("Sub")\n .select()\n .execute(glue)\n .await;\n')),(0,i.yg)("h3",{id:"derived-subquery-with-projection"},"Derived Subquery with Projection"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Item")\n .select()\n .project("item_id")\n .alias_as("Sub")\n .select()\n .execute(glue)\n .await;\n')),(0,i.yg)("h3",{id:"derived-subquery-with-join"},"Derived Subquery with Join"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Item")\n .alias_as("i")\n .select()\n .join_as("Category", "c")\n .on("c.category_id = i.category_id")\n .alias_as("Sub")\n .select()\n .project("item_name")\n .project("category_name")\n .execute(glue)\n .await;\n')),(0,i.yg)("h3",{id:"derived-subquery-with-group-by-and-having"},"Derived Subquery with Group By and Having"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Category")\n .select()\n .project("category_name")\n .alias_as("Sub1")\n .select()\n .group_by("category_name")\n .having("category_name = \'Meat\'")\n .alias_as("Sub2")\n .select()\n .execute(glue)\n .await;\n')),(0,i.yg)("h3",{id:"derived-subquery-with-order-by"},"Derived Subquery with Order By"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Item")\n .select()\n .order_by("price DESC")\n .alias_as("Sub")\n .select()\n .execute(glue)\n .await;\n')),(0,i.yg)("h3",{id:"derived-subquery-with-offset-and-limit"},"Derived Subquery with Offset and Limit"),(0,i.yg)("p",null,"This example shows how to create a derived subquery combined with both the ",(0,i.yg)("inlineCode",{parentName:"p"},"offset")," and ",(0,i.yg)("inlineCode",{parentName:"p"},"limit")," methods to control the range of rows returned:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Item")\n .select()\n .offset(3)\n .limit(1)\n .alias_as("Sub")\n .select()\n .execute(glue)\n .await;\n')))}y.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/01a12966.469b19f8.js b/docs/0.16.0/assets/js/01a12966.469b19f8.js new file mode 100644 index 00000000..6ee40044 --- /dev/null +++ b/docs/0.16.0/assets/js/01a12966.469b19f8.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[79],{5680:(e,n,t)=>{t.d(n,{xA:()=>u,yg:()=>y});var r=t(6540);function o(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function a(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function i(e){for(var n=1;n=0||(o[t]=e[t]);return o}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var l=r.createContext({}),c=function(e){var n=r.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},u=function(e){var n=c(e.components);return r.createElement(l.Provider,{value:n},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},g=r.forwardRef((function(e,n){var t=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=c(t),g=o,y=p["".concat(l,".").concat(g)]||p[g]||d[g]||a;return t?r.createElement(y,i(i({ref:n},u),{},{components:t})):r.createElement(y,i({ref:n},u))}));function y(e,n){var t=arguments,o=n&&n.mdxType;if("string"==typeof e||o){var a=t.length,i=new Array(a);i[0]=g;var s={};for(var l in n)hasOwnProperty.call(n,l)&&(s[l]=n[l]);s.originalType=e,s[p]="string"==typeof e?e:o,i[1]=s;for(var c=2;c{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>i,default:()=>d,frontMatter:()=>a,metadata:()=>s,toc:()=>c});var r=t(8168),o=(t(6540),t(5680));const a={sidebar_position:3},i="Node.js",s={unversionedId:"getting-started/nodejs",id:"getting-started/nodejs",title:"Node.js",description:"This guide will help you get started with GlueSQL in a Node.js project. First, install the gluesql package using npm by running the following command in your terminal:",source:"@site/docs/getting-started/nodejs.md",sourceDirName:"getting-started",slug:"/getting-started/nodejs",permalink:"/docs/0.16.0/getting-started/nodejs",draft:!1,tags:[],version:"current",sidebarPosition:3,frontMatter:{sidebar_position:3},sidebar:"autoSidebar",previous:{title:"JavaScript (Web Browser)",permalink:"/docs/0.16.0/getting-started/javascript-web"},next:{title:"Command-Line Interface",permalink:"/docs/0.16.0/getting-started/cli"}},l={},c=[],u={toc:c},p="wrapper";function d(e){let{components:n,...t}=e;return(0,o.yg)(p,(0,r.A)({},u,t,{components:n,mdxType:"MDXLayout"}),(0,o.yg)("h1",{id:"nodejs"},"Node.js"),(0,o.yg)("p",null,"This guide will help you get started with GlueSQL in a Node.js project. First, install the ",(0,o.yg)("inlineCode",{parentName:"p"},"gluesql")," package using npm by running the following command in your terminal:"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-sh"},"npm install gluesql\n")),(0,o.yg)("p",null,"Alternatively, you can add it as a dependency in your ",(0,o.yg)("inlineCode",{parentName:"p"},"package.json")," file:"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-json"},'{\n "dependencies": {\n "gluesql": "latest"\n }\n}\n')),(0,o.yg)("p",null,"Please note that the Node.js version of GlueSQL currently supports only non-persistent memory storage."),(0,o.yg)("p",null,"Next, you can use GlueSQL in your Node.js project by following this simple example:"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-javascript"},"const { gluesql } = require('gluesql');\nconst db = gluesql();\n\nasync function run() {\n await db.query(`\n CREATE TABLE User (id INTEGER, name TEXT);\n CREATE TABLE Device (name TEXT, userId INTEGER);\n INSERT INTO User VALUES (1, 'glue'), (2, 'sticky'), (3, 'watt');\n INSERT INTO Device VALUES ('Phone', 1), ('Mic', 1), ('Monitor', 3), ('Mouse', 2), ('Touchpad', 2);\n `);\n\n const sql = `\n SELECT\n u.name as user,\n d.name as device\n FROM User u\n JOIN Device d ON u.id = d.userId\n `;\n const [{ rows }] = await db.query(sql);\n console.table(rows);\n}\n\nrun();\n")),(0,o.yg)("p",null,"This example demonstrates how to create tables, insert data, and perform a join query using GlueSQL in Node.js."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/01a85c17.de44d5e4.js b/docs/0.16.0/assets/js/01a85c17.de44d5e4.js new file mode 100644 index 00000000..0399d766 --- /dev/null +++ b/docs/0.16.0/assets/js/01a85c17.de44d5e4.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[8209],{6669:(e,t,a)=>{a.d(t,{A:()=>E});var l=a(6540),r=a(53),n=a(9408),s=a(4581),i=a(5489),c=a(1312);const m={sidebar:"sidebar_re4s",sidebarItemTitle:"sidebarItemTitle_pO2u",sidebarItemList:"sidebarItemList_Yudw",sidebarItem:"sidebarItem__DBe",sidebarItemLink:"sidebarItemLink_mo7H",sidebarItemLinkActive:"sidebarItemLinkActive_I1ZP"};function o(e){let{sidebar:t}=e;return l.createElement("aside",{className:"col col--3"},l.createElement("nav",{className:(0,r.A)(m.sidebar,"thin-scrollbar"),"aria-label":(0,c.T)({id:"theme.blog.sidebar.navAriaLabel",message:"Blog recent posts navigation",description:"The ARIA label for recent posts in the blog sidebar"})},l.createElement("div",{className:(0,r.A)(m.sidebarItemTitle,"margin-bottom--md")},t.title),l.createElement("ul",{className:(0,r.A)(m.sidebarItemList,"clean-list")},t.items.map((e=>l.createElement("li",{key:e.permalink,className:m.sidebarItem},l.createElement(i.A,{isNavLink:!0,to:e.permalink,className:m.sidebarItemLink,activeClassName:m.sidebarItemLinkActive},e.title)))))))}var u=a(5600);function g(e){let{sidebar:t}=e;return l.createElement("ul",{className:"menu__list"},t.items.map((e=>l.createElement("li",{key:e.permalink,className:"menu__list-item"},l.createElement(i.A,{isNavLink:!0,to:e.permalink,className:"menu__link",activeClassName:"menu__link--active"},e.title)))))}function b(e){return l.createElement(u.GX,{component:g,props:e})}function d(e){let{sidebar:t}=e;const a=(0,s.l)();return t?.items.length?"mobile"===a?l.createElement(b,{sidebar:t}):l.createElement(o,{sidebar:t}):null}function E(e){const{sidebar:t,toc:a,children:s,...i}=e,c=t&&t.items.length>0;return l.createElement(n.A,i,l.createElement("div",{className:"container margin-vert--lg"},l.createElement("div",{className:"row"},l.createElement(d,{sidebar:t}),l.createElement("main",{className:(0,r.A)("col",{"col--7":c,"col--9 col--offset-1":!c}),itemScope:!0,itemType:"http://schema.org/Blog"},s),a&&l.createElement("div",{className:"col col--2"},a))))}},9158:(e,t,a)=>{a.r(t),a.d(t,{default:()=>E});var l=a(6540),r=a(53),n=a(1312);const s=()=>(0,n.T)({id:"theme.tags.tagsPageTitle",message:"Tags",description:"The title of the tag list page"});var i=a(1003),c=a(7559),m=a(6669),o=a(6133);const u={tag:"tag_Nnez"};function g(e){let{letterEntry:t}=e;return l.createElement("article",null,l.createElement("h2",null,t.letter),l.createElement("ul",{className:"padding--none"},t.tags.map((e=>l.createElement("li",{key:e.permalink,className:u.tag},l.createElement(o.A,e))))),l.createElement("hr",null))}function b(e){let{tags:t}=e;const a=function(e){const t={};return Object.values(e).forEach((e=>{const a=function(e){return e[0].toUpperCase()}(e.label);t[a]??=[],t[a].push(e)})),Object.entries(t).sort(((e,t)=>{let[a]=e,[l]=t;return a.localeCompare(l)})).map((e=>{let[t,a]=e;return{letter:t,tags:a.sort(((e,t)=>e.label.localeCompare(t.label)))}}))}(t);return l.createElement("section",{className:"margin-vert--lg"},a.map((e=>l.createElement(g,{key:e.letter,letterEntry:e}))))}var d=a(1463);function E(e){let{tags:t,sidebar:a}=e;const n=s();return l.createElement(i.e3,{className:(0,r.A)(c.G.wrapper.blogPages,c.G.page.blogTagsListPage)},l.createElement(i.be,{title:n}),l.createElement(d.A,{tag:"blog_tags_list"}),l.createElement(m.A,{sidebar:a},l.createElement("h1",null,n),l.createElement(b,{tags:t})))}},6133:(e,t,a)=>{a.d(t,{A:()=>i});var l=a(6540),r=a(53),n=a(5489);const s={tag:"tag_zVej",tagRegular:"tagRegular_sFm0",tagWithCount:"tagWithCount_h2kH"};function i(e){let{permalink:t,label:a,count:i}=e;return l.createElement(n.A,{href:t,className:(0,r.A)(s.tag,i?s.tagWithCount:s.tagRegular)},a,i&&l.createElement("span",null,i))}}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/02aa4531.17b335fe.js b/docs/0.16.0/assets/js/02aa4531.17b335fe.js new file mode 100644 index 00000000..7e28d013 --- /dev/null +++ b/docs/0.16.0/assets/js/02aa4531.17b335fe.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[126],{5680:(e,n,t)=>{t.d(n,{xA:()=>u,yg:()=>g});var r=t(6540);function a(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function i(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function o(e){for(var n=1;n=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var s=r.createContext({}),l=function(e){var n=r.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):o(o({},n),e)),t},u=function(e){var n=l(e.components);return r.createElement(s.Provider,{value:n},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},m=r.forwardRef((function(e,n){var t=e.components,a=e.mdxType,i=e.originalType,s=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),d=l(t),m=a,g=d["".concat(s,".").concat(m)]||d[m]||p[m]||i;return t?r.createElement(g,o(o({ref:n},u),{},{components:t})):r.createElement(g,o({ref:n},u))}));function g(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var i=t.length,o=new Array(i);o[0]=m;var c={};for(var s in n)hasOwnProperty.call(n,s)&&(c[s]=n[s]);c.originalType=e,c[d]="string"==typeof e?e:a,o[1]=c;for(var l=2;l{t.r(n),t.d(n,{assets:()=>s,contentTitle:()=>o,default:()=>p,frontMatter:()=>i,metadata:()=>c,toc:()=>l});var r=t(8168),a=(t(6540),t(5680));const i={},o="Conversion",c={unversionedId:"ast-builder/functions/math/conversion",id:"ast-builder/functions/math/conversion",title:"Conversion",description:"The AST (Abstract Syntax Tree) Builder in GlueSQL provides mathematical conversion functions like degrees and radians. These functions convert angles expressed in radians to degrees and vice versa.",source:"@site/docs/ast-builder/functions/math/conversion.md",sourceDirName:"ast-builder/functions/math",slug:"/ast-builder/functions/math/conversion",permalink:"/docs/0.16.0/ast-builder/functions/math/conversion",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"Basic Arithmetic",permalink:"/docs/0.16.0/ast-builder/functions/math/basic-arithmetic"},next:{title:"Logarithmic and Exponential",permalink:"/docs/0.16.0/ast-builder/functions/math/logarithmic-and-exponential"}},s={},l=[{value:"Degrees Function",id:"degrees-function",level:2},{value:"Radians Function",id:"radians-function",level:2}],u={toc:l},d="wrapper";function p(e){let{components:n,...t}=e;return(0,a.yg)(d,(0,r.A)({},u,t,{components:n,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"conversion"},"Conversion"),(0,a.yg)("p",null,"The AST (Abstract Syntax Tree) Builder in GlueSQL provides mathematical conversion functions like ",(0,a.yg)("inlineCode",{parentName:"p"},"degrees")," and ",(0,a.yg)("inlineCode",{parentName:"p"},"radians"),". These functions convert angles expressed in radians to degrees and vice versa."),(0,a.yg)("p",null,"For the sake of this tutorial, we'll assume there's a table named ",(0,a.yg)("inlineCode",{parentName:"p"},"Number")," with columns ",(0,a.yg)("inlineCode",{parentName:"p"},"input")," (of type ",(0,a.yg)("inlineCode",{parentName:"p"},"INTEGER"),") and ",(0,a.yg)("inlineCode",{parentName:"p"},"number")," (of type ",(0,a.yg)("inlineCode",{parentName:"p"},"FLOAT"),")."),(0,a.yg)("h2",{id:"degrees-function"},"Degrees Function"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"degrees")," function converts an angle from radians to degrees."),(0,a.yg)("p",null,"You can call this function in two ways in GlueSQL:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Number")\n .select()\n .project("input")\n .project(degrees("number")) // Method 1: Using the degrees function directly\n .project(col("number").degrees()) // Method 2: Calling the degrees method on a column\n .execute(glue)\n .await;\n')),(0,a.yg)("h2",{id:"radians-function"},"Radians Function"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"radians")," function converts an angle from degrees to radians."),(0,a.yg)("p",null,"Just like with the ",(0,a.yg)("inlineCode",{parentName:"p"},"degrees")," function, there are two ways to call this function:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Number")\n .select()\n .project("input")\n .project(radians("number")) // Method 1: Using the radians function directly\n .project(col("number").radians()) // Method 2: Calling the radians method on a column\n .execute(glue)\n .await;\n')))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/02bfc02d.c93d2576.js b/docs/0.16.0/assets/js/02bfc02d.c93d2576.js new file mode 100644 index 00000000..8286bcca --- /dev/null +++ b/docs/0.16.0/assets/js/02bfc02d.c93d2576.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[6858],{5680:(e,t,n)=>{n.d(t,{xA:()=>s,yg:()=>d});var r=n(6540);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var m=r.createContext({}),c=function(e){var t=r.useContext(m),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},s=function(e){var t=c(e.components);return r.createElement(m.Provider,{value:t},e.children)},u="mdxType",g={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},p=r.forwardRef((function(e,t){var n=e.components,i=e.mdxType,a=e.originalType,m=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),u=c(n),p=i,d=u["".concat(m,".").concat(p)]||u[p]||g[p]||a;return n?r.createElement(d,o(o({ref:t},s),{},{components:n})):r.createElement(d,o({ref:t},s))}));function d(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var a=n.length,o=new Array(a);o[0]=p;var l={};for(var m in t)hasOwnProperty.call(t,m)&&(l[m]=t[m]);l.originalType=e,l[u]="string"==typeof e?e:i,o[1]=l;for(var c=2;c{n.r(t),n.d(t,{assets:()=>m,contentTitle:()=>o,default:()=>g,frontMatter:()=>a,metadata:()=>l,toc:()=>c});var r=n(8168),i=(n(6540),n(5680));const a={},o="Trimming",l={unversionedId:"ast-builder/functions/text/trimming",id:"ast-builder/functions/text/trimming",title:"Trimming",description:"GlueSQL provides several text trimming functions that allow you to remove leading or trailing characters from a text string.",source:"@site/docs/ast-builder/functions/text/trimming.md",sourceDirName:"ast-builder/functions/text",slug:"/ast-builder/functions/text/trimming",permalink:"/docs/0.16.0/ast-builder/functions/text/trimming",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"Text Manipulation",permalink:"/docs/0.16.0/ast-builder/functions/text/text-manipulation"},next:{title:"Basic Arithmetic",permalink:"/docs/0.16.0/ast-builder/functions/math/basic-arithmetic"}},m={},c=[{value:"Right Trimming - rtrim",id:"right-trimming---rtrim",level:2},{value:"Left Trimming - ltrim",id:"left-trimming---ltrim",level:2},{value:"Right and Left Trimming",id:"right-and-left-trimming",level:2}],s={toc:c},u="wrapper";function g(e){let{components:t,...n}=e;return(0,i.yg)(u,(0,r.A)({},s,n,{components:t,mdxType:"MDXLayout"}),(0,i.yg)("h1",{id:"trimming"},"Trimming"),(0,i.yg)("p",null,"GlueSQL provides several text trimming functions that allow you to remove leading or trailing characters from a text string."),(0,i.yg)("p",null,"For this tutorial, we assume there's a table named ",(0,i.yg)("inlineCode",{parentName:"p"},"Food")," with an ",(0,i.yg)("inlineCode",{parentName:"p"},"id")," column of ",(0,i.yg)("inlineCode",{parentName:"p"},"INTEGER")," type and a ",(0,i.yg)("inlineCode",{parentName:"p"},"name")," column of ",(0,i.yg)("inlineCode",{parentName:"p"},"TEXT")," type."),(0,i.yg)("h2",{id:"right-trimming---rtrim"},"Right Trimming - rtrim"),(0,i.yg)("p",null,"The ",(0,i.yg)("inlineCode",{parentName:"p"},"rtrim")," function removes trailing characters from a text string. You can specify the characters to be removed as an argument to the function. If no argument is provided, it trims spaces by default."),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-rust"},'// Trims trailing spaces from "chicken "\nlet test_text = text("chicken ").rtrim(Some(text(" ")));\n\nlet actual = table("Food")\n .insert()\n .columns("id, name")\n .values(vec![vec![num(1), test_text]])\n .execute(glue)\n .await;\n')),(0,i.yg)("h2",{id:"left-trimming---ltrim"},"Left Trimming - ltrim"),(0,i.yg)("p",null,"The ",(0,i.yg)("inlineCode",{parentName:"p"},"ltrim")," function removes leading characters from a text string. You can specify the characters to be removed as an argument to the function. If no argument is provided, it trims spaces by default."),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-rust"},'// Trims leading spaces from " chicken"\nlet test_text = ltrim(text(" chicken"), Some(text(" ")));\n\nlet actual = table("Food")\n .insert()\n .columns("id, name")\n .values(vec![vec![num(2), test_text]])\n .execute(glue)\n .await;\n')),(0,i.yg)("h2",{id:"right-and-left-trimming"},"Right and Left Trimming"),(0,i.yg)("p",null,"You can combine ",(0,i.yg)("inlineCode",{parentName:"p"},"rtrim")," and ",(0,i.yg)("inlineCode",{parentName:"p"},"ltrim")," to trim both sides of a string:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-rust"},'// Trims leading "ch" and trailing spaces from "chicken"\nlet test_text = text("chicken").ltrim(Some(text("ch"))).rtrim(None);\n\nlet actual = table("Food")\n .insert()\n .columns("id, name")\n .values(vec![vec![num(3), test_text]])\n .execute(glue)\n .await;\n')),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-rust"},'// Trims trailing "en" and leading spaces from "chicken"\nlet test_text = text("chicken").rtrim(Some(text("en"))).ltrim(None);\n\nlet actual = table("Food")\n .insert()\n .columns("id, name")\n .values(vec![vec![num(4), test_text]])\n .execute(glue)\n .await;\n')))}g.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/037683de.b9938f31.js b/docs/0.16.0/assets/js/037683de.b9938f31.js new file mode 100644 index 00000000..64a63669 --- /dev/null +++ b/docs/0.16.0/assets/js/037683de.b9938f31.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[1661],{5680:(e,t,a)=>{a.d(t,{xA:()=>s,yg:()=>g});var n=a(6540);function l(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function i(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function r(e){for(var t=1;t=0||(l[a]=e[a]);return l}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(l[a]=e[a])}return l}var u=n.createContext({}),p=function(e){var t=n.useContext(u),a=t;return e&&(a="function"==typeof e?e(t):r(r({},t),e)),a},s=function(e){var t=p(e.components);return n.createElement(u.Provider,{value:t},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var a=e.components,l=e.mdxType,i=e.originalType,u=e.parentName,s=o(e,["components","mdxType","originalType","parentName"]),d=p(a),m=l,g=d["".concat(u,".").concat(m)]||d[m]||c[m]||i;return a?n.createElement(g,r(r({ref:t},s),{},{components:a})):n.createElement(g,r({ref:t},s))}));function g(e,t){var a=arguments,l=t&&t.mdxType;if("string"==typeof e||l){var i=a.length,r=new Array(i);r[0]=m;var o={};for(var u in t)hasOwnProperty.call(t,u)&&(o[u]=t[u]);o.originalType=e,o[d]="string"==typeof e?e:l,r[1]=o;for(var p=2;p{a.r(t),a.d(t,{assets:()=>u,contentTitle:()=>r,default:()=>c,frontMatter:()=>i,metadata:()=>o,toc:()=>p});var n=a(8168),l=(a(6540),a(5680));const i={sidebar_position:4},r="Updating Data",o={unversionedId:"ast-builder/statements/data-manipulation/updating-data",id:"ast-builder/statements/data-manipulation/updating-data",title:"Updating Data",description:"In this section, we will discuss how to update data in a table using GlueSQL.",source:"@site/docs/ast-builder/statements/data-manipulation/updating-data.md",sourceDirName:"ast-builder/statements/data-manipulation",slug:"/ast-builder/statements/data-manipulation/updating-data",permalink:"/docs/0.16.0/ast-builder/statements/data-manipulation/updating-data",draft:!1,tags:[],version:"current",sidebarPosition:4,frontMatter:{sidebar_position:4},sidebar:"autoSidebar",previous:{title:"Inserting Data",permalink:"/docs/0.16.0/ast-builder/statements/data-manipulation/inserting-data"},next:{title:"Deleting Data",permalink:"/docs/0.16.0/ast-builder/statements/data-manipulation/deleting-data"}},u={},p=[{value:"Basic Update",id:"basic-update",level:2},{value:"Update with Multiple Columns",id:"update-with-multiple-columns",level:2},{value:"Update with Filter",id:"update-with-filter",level:2}],s={toc:p},d="wrapper";function c(e){let{components:t,...a}=e;return(0,l.yg)(d,(0,n.A)({},s,a,{components:t,mdxType:"MDXLayout"}),(0,l.yg)("h1",{id:"updating-data"},"Updating Data"),(0,l.yg)("p",null,"In this section, we will discuss how to update data in a table using GlueSQL."),(0,l.yg)("h2",{id:"basic-update"},"Basic Update"),(0,l.yg)("p",null,"To update data in a table, you can use the ",(0,l.yg)("inlineCode",{parentName:"p"},"update")," method on a table object, followed by the ",(0,l.yg)("inlineCode",{parentName:"p"},"set")," method to specify the column and the new value. You can then use the ",(0,l.yg)("inlineCode",{parentName:"p"},"execute")," method to apply the changes."),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Foo")\n .update()\n .set("score", col("score").div(10))\n .execute(glue)\n .await;\nlet expected = Ok(Payload::Update(3));\ntest(actual, expected);\n')),(0,l.yg)("p",null,"This code updates all rows in the table ",(0,l.yg)("inlineCode",{parentName:"p"},"Foo"),", dividing the ",(0,l.yg)("inlineCode",{parentName:"p"},"score")," column value by 10."),(0,l.yg)("h2",{id:"update-with-multiple-columns"},"Update with Multiple Columns"),(0,l.yg)("p",null,"To update multiple columns, you can chain multiple ",(0,l.yg)("inlineCode",{parentName:"p"},"set")," methods with the desired column names and new values."),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Foo")\n .update()\n .set("score", "score * 2 + 5")\n .set("flag", col("flag").negate())\n .execute(glue)\n .await;\nlet expected = Ok(Payload::Update(3));\ntest(actual, expected);\n')),(0,l.yg)("p",null,"This code updates all rows in the table ",(0,l.yg)("inlineCode",{parentName:"p"},"Foo"),", applying the following changes:"),(0,l.yg)("ol",null,(0,l.yg)("li",{parentName:"ol"},"The ",(0,l.yg)("inlineCode",{parentName:"li"},"score")," column value is multiplied by 2 and 5 is added."),(0,l.yg)("li",{parentName:"ol"},"The ",(0,l.yg)("inlineCode",{parentName:"li"},"flag")," column value is negated (i.e., true becomes false and false becomes true).")),(0,l.yg)("h2",{id:"update-with-filter"},"Update with Filter"),(0,l.yg)("p",null,"If you want to update only specific rows, you can use the ",(0,l.yg)("inlineCode",{parentName:"p"},"filter")," method to provide a condition that the rows must meet."),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Foo")\n .update()\n .set("score", "score * 2 + 5")\n .set("flag", col("flag").negate())\n .filter(col("score").lte(30))\n .execute(glue)\n .await;\nlet expected = Ok(Payload::Update(2));\ntest(actual, expected);\n')),(0,l.yg)("p",null,"This code updates the rows in the table ",(0,l.yg)("inlineCode",{parentName:"p"},"Foo")," where the ",(0,l.yg)("inlineCode",{parentName:"p"},"score")," column value is less than or equal to 30. The ",(0,l.yg)("inlineCode",{parentName:"p"},"score")," and ",(0,l.yg)("inlineCode",{parentName:"p"},"flag")," column values are updated as described in the previous example."))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/045be9fd.bc59c80a.js b/docs/0.16.0/assets/js/045be9fd.bc59c80a.js new file mode 100644 index 00000000..78923088 --- /dev/null +++ b/docs/0.16.0/assets/js/045be9fd.bc59c80a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[106],{2431:s=>{s.exports=JSON.parse('{"permalink":"/docs/0.16.0/blog/tags/sql","page":1,"postsPerPage":10,"totalPages":1,"totalCount":1,"blogDescription":"Blog","blogTitle":"Blog"}')}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/0544f90b.ccc9e299.js b/docs/0.16.0/assets/js/0544f90b.ccc9e299.js new file mode 100644 index 00000000..236fd2bb --- /dev/null +++ b/docs/0.16.0/assets/js/0544f90b.ccc9e299.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[1219],{5680:(e,t,n)=>{n.d(t,{xA:()=>c,yg:()=>y});var a=n(6540);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var l=a.createContext({}),d=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},c=function(e){var t=d(e.components);return a.createElement(l.Provider,{value:t},e.children)},p="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,l=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),p=d(n),m=i,y=p["".concat(l,".").concat(m)]||p[m]||u[m]||o;return n?a.createElement(y,r(r({ref:t},c),{},{components:n})):a.createElement(y,r({ref:t},c))}));function y(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,r=new Array(o);r[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[p]="string"==typeof e?e:i,r[1]=s;for(var d=2;d{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>r,default:()=>u,frontMatter:()=>o,metadata:()=>s,toc:()=>d});var a=n(8168),i=(n(6540),n(5680));const o={sidebar_position:3},r="CREATE INDEX",s={unversionedId:"sql-syntax/statements/data-definition/create-index",id:"sql-syntax/statements/data-definition/create-index",title:"CREATE INDEX",description:"CREATE INDEX statement is used to create an index on one or more columns of a table. Indexes can improve query performance by allowing the database to quickly locate rows with specific column values. They can also be used with the ORDER BY clause to improve sorting performance. An index can be thought of as a data structure that maps the values of a specific column or columns to the corresponding rows in a table. This mapping allows the database to perform lookups and sorting operations more efficiently, as it does not have to scan the entire table.",source:"@site/docs/sql-syntax/statements/data-definition/create-index.md",sourceDirName:"sql-syntax/statements/data-definition",slug:"/sql-syntax/statements/data-definition/create-index",permalink:"/docs/0.16.0/sql-syntax/statements/data-definition/create-index",draft:!1,tags:[],version:"current",sidebarPosition:3,frontMatter:{sidebar_position:3},sidebar:"autoSidebar",previous:{title:"DROP TABLE",permalink:"/docs/0.16.0/sql-syntax/statements/data-definition/drop-table"},next:{title:"DROP INDEX",permalink:"/docs/0.16.0/sql-syntax/statements/data-definition/drop-index"}},l={},d=[{value:"Syntax",id:"syntax",level:2},{value:"Example",id:"example",level:2},{value:"Using Index with ORDER BY",id:"using-index-with-order-by",level:2}],c={toc:d},p="wrapper";function u(e){let{components:t,...n}=e;return(0,i.yg)(p,(0,a.A)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,i.yg)("h1",{id:"create-index"},"CREATE INDEX"),(0,i.yg)("p",null,(0,i.yg)("inlineCode",{parentName:"p"},"CREATE INDEX")," statement is used to create an index on one or more columns of a table. Indexes can improve query performance by allowing the database to quickly locate rows with specific column values. They can also be used with the ",(0,i.yg)("inlineCode",{parentName:"p"},"ORDER BY")," clause to improve sorting performance. An index can be thought of as a data structure that maps the values of a specific column or columns to the corresponding rows in a table. This mapping allows the database to perform lookups and sorting operations more efficiently, as it does not have to scan the entire table."),(0,i.yg)("h2",{id:"syntax"},"Syntax"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE INDEX index_name ON table_name (column_name_expression);\n")),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("inlineCode",{parentName:"li"},"index_name"),": The name of the index. It is recommended to use a descriptive name that indicates the purpose of the index, such as the column(s) it is based on."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("inlineCode",{parentName:"li"},"table_name"),": The name of the table on which the index is to be created."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("inlineCode",{parentName:"li"},"column_name_expression"),": The column name or expression on which the index is based. Only single column indexes are supported. If a column expression is used, it should be a simple arithmetic operation, such as addition or multiplication.")),(0,i.yg)("h2",{id:"example"},"Example"),(0,i.yg)("p",null,"Consider the following table called ",(0,i.yg)("inlineCode",{parentName:"p"},"Students"),":"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE Students (\n id INTEGER,\n age INTEGER,\n name TEXT\n);\n")),(0,i.yg)("p",null,"You can create an index on the ",(0,i.yg)("inlineCode",{parentName:"p"},"id")," column with the following statement:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE INDEX idx_id ON Students (id);\n")),(0,i.yg)("p",null,"You can also create an index on a column expression, such as ",(0,i.yg)("inlineCode",{parentName:"p"},"age * 2"),":"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE INDEX idx_age ON Students (age * 2);\n")),(0,i.yg)("p",null,"Note that composite indexes (indexes on multiple columns) are not supported. These types of indexes can provide additional performance benefits in certain situations, but they also come with added complexity and increased storage requirements."),(0,i.yg)("h2",{id:"using-index-with-order-by"},"Using Index with ORDER BY"),(0,i.yg)("p",null,"Indexes can improve the performance of the ",(0,i.yg)("inlineCode",{parentName:"p"},"ORDER BY")," clause. When an index exists on the column specified in the ",(0,i.yg)("inlineCode",{parentName:"p"},"ORDER BY")," clause, the database can use the index to sort the data more efficiently. This is because the index already provides a sorted view of the data, allowing the database to avoid the cost of sorting the entire table during query execution."),(0,i.yg)("p",null,"For example, if you have the following query:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT * FROM Students ORDER BY id ASC;\n")),(0,i.yg)("p",null,"The database can use the ",(0,i.yg)("inlineCode",{parentName:"p"},"idx_id")," index created earlier to sort the data more quickly than without an index. Keep in mind that the performance gains from using an index with the ",(0,i.yg)("inlineCode",{parentName:"p"},"ORDER BY")," clause will depend on the size of the table, the distribution of the data, and the specific database implementation."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/06322d53.4d22d233.js b/docs/0.16.0/assets/js/06322d53.4d22d233.js new file mode 100644 index 00000000..406b24a8 --- /dev/null +++ b/docs/0.16.0/assets/js/06322d53.4d22d233.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[4972],{5680:(e,n,t)=>{t.d(n,{xA:()=>c,yg:()=>y});var r=t(6540);function a(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function l(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function i(e){for(var n=1;n=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var s=r.createContext({}),p=function(e){var n=r.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},c=function(e){var n=p(e.components);return r.createElement(s.Provider,{value:n},e.children)},u="mdxType",g={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},m=r.forwardRef((function(e,n){var t=e.components,a=e.mdxType,l=e.originalType,s=e.parentName,c=o(e,["components","mdxType","originalType","parentName"]),u=p(t),m=a,y=u["".concat(s,".").concat(m)]||u[m]||g[m]||l;return t?r.createElement(y,i(i({ref:n},c),{},{components:t})):r.createElement(y,i({ref:n},c))}));function y(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var l=t.length,i=new Array(l);i[0]=m;var o={};for(var s in n)hasOwnProperty.call(n,s)&&(o[s]=n[s]);o.originalType=e,o[u]="string"==typeof e?e:a,i[1]=o;for(var p=2;p{t.r(n),t.d(n,{assets:()=>s,contentTitle:()=>i,default:()=>g,frontMatter:()=>l,metadata:()=>o,toc:()=>p});var r=t(8168),a=(t(6540),t(5680));const l={},i="INITCAP",o={unversionedId:"sql-syntax/functions/text/initcap",id:"sql-syntax/functions/text/initcap",title:"INITCAP",description:"The INITCAP function in SQL is used to capitalize the first letter of each word in a string and convert the rest of the characters to lowercase.",source:"@site/docs/sql-syntax/functions/text/initcap.md",sourceDirName:"sql-syntax/functions/text",slug:"/sql-syntax/functions/text/initcap",permalink:"/docs/0.16.0/sql-syntax/functions/text/initcap",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"FIND_IDX",permalink:"/docs/0.16.0/sql-syntax/functions/text/find-idx"},next:{title:"LEFT",permalink:"/docs/0.16.0/sql-syntax/functions/text/left"}},s={},p=[{value:"Syntax",id:"syntax",level:2},{value:"Parameters",id:"parameters",level:2},{value:"Examples",id:"examples",level:2}],c={toc:p},u="wrapper";function g(e){let{components:n,...t}=e;return(0,a.yg)(u,(0,r.A)({},c,t,{components:n,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"initcap"},"INITCAP"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"INITCAP")," function in SQL is used to capitalize the first letter of each word in a string and convert the rest of the characters to lowercase."),(0,a.yg)("h2",{id:"syntax"},"Syntax"),(0,a.yg)("p",null,"The syntax for the ",(0,a.yg)("inlineCode",{parentName:"p"},"INITCAP")," function in SQL is:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"INITCAP( string )\n")),(0,a.yg)("h2",{id:"parameters"},"Parameters"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"string"),": The input string on which the capitalization will be applied.")),(0,a.yg)("h2",{id:"examples"},"Examples"),(0,a.yg)("p",null,"Let's consider a few examples to understand how to use the ",(0,a.yg)("inlineCode",{parentName:"p"},"INITCAP")," function."),(0,a.yg)("p",null,"Create a table named ",(0,a.yg)("inlineCode",{parentName:"p"},"Item")," with a column ",(0,a.yg)("inlineCode",{parentName:"p"},"name"),":"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE Item (\n name TEXT DEFAULT 'abcd',\n);\n")),(0,a.yg)("p",null,"Insert some data into the ",(0,a.yg)("inlineCode",{parentName:"p"},"Item")," table:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO Item VALUES\n('h/i jk'),\n(NULL),\n('H/I JK');\n")),(0,a.yg)("p",null,"Select rows where the ",(0,a.yg)("inlineCode",{parentName:"p"},"INITCAP(name)")," is equal to 'H/I Jk':"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT name FROM Item WHERE INITCAP(name) = 'H/I Jk';\n")),(0,a.yg)("p",null,"This will return the rows with 'h/i jk' and 'H/I JK', as both have the same result after applying the ",(0,a.yg)("inlineCode",{parentName:"p"},"INITCAP")," function."),(0,a.yg)("p",null,"Apply the ",(0,a.yg)("inlineCode",{parentName:"p"},"INITCAP")," function to the ",(0,a.yg)("inlineCode",{parentName:"p"},"name")," column and return the result:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT INITCAP(name) FROM Item;\n")),(0,a.yg)("p",null,"This will return 'H/I Jk', NULL, and 'H/I Jk' for the three rows, respectively."),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"INITCAP")," function expects a string value as the input. If a non-string value is passed as the input, it will throw an error:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT INITCAP(1) FROM Item;\n")),(0,a.yg)("p",null,"This will throw an error because the ",(0,a.yg)("inlineCode",{parentName:"p"},"INITCAP")," function expects a string value as the input."),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"INITCAP")," function expects a single argument. If no arguments are provided, it will throw an error:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT INITCAP() FROM Item;\n")),(0,a.yg)("p",null,"This will throw an error because the ",(0,a.yg)("inlineCode",{parentName:"p"},"INITCAP")," function expects a single argument."),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"INITCAP")," function does not support named arguments. If a named argument is provided, it will throw an error:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT INITCAP(a => 2) FROM Item;\n")),(0,a.yg)("p",null,"This will throw an error because the ",(0,a.yg)("inlineCode",{parentName:"p"},"INITCAP")," function does not support named arguments."))}g.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/07294b24.663c5d97.js b/docs/0.16.0/assets/js/07294b24.663c5d97.js new file mode 100644 index 00000000..d4fedfe0 --- /dev/null +++ b/docs/0.16.0/assets/js/07294b24.663c5d97.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[3055],{5680:(e,n,t)=>{t.d(n,{xA:()=>u,yg:()=>f});var r=t(6540);function a(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function l(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function o(e){for(var n=1;n=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var d=r.createContext({}),p=function(e){var n=r.useContext(d),t=n;return e&&(t="function"==typeof e?e(n):o(o({},n),e)),t},u=function(e){var n=p(e.components);return r.createElement(d.Provider,{value:n},e.children)},c="mdxType",s={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},g=r.forwardRef((function(e,n){var t=e.components,a=e.mdxType,l=e.originalType,d=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),c=p(t),g=a,f=c["".concat(d,".").concat(g)]||c[g]||s[g]||l;return t?r.createElement(f,o(o({ref:n},u),{},{components:t})):r.createElement(f,o({ref:n},u))}));function f(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var l=t.length,o=new Array(l);o[0]=g;var i={};for(var d in n)hasOwnProperty.call(n,d)&&(i[d]=n[d]);i.originalType=e,i[c]="string"==typeof e?e:a,o[1]=i;for(var p=2;p{t.r(n),t.d(n,{assets:()=>d,contentTitle:()=>o,default:()=>s,frontMatter:()=>l,metadata:()=>i,toc:()=>p});var r=t(8168),a=(t(6540),t(5680));const l={},o="Padding",i={unversionedId:"ast-builder/functions/text/padding",id:"ast-builder/functions/text/padding",title:"Padding",description:"The AST Builder API in GlueSQL allows you to execute lpad and rpad functions for text padding.",source:"@site/docs/ast-builder/functions/text/padding.md",sourceDirName:"ast-builder/functions/text",slug:"/ast-builder/functions/text/padding",permalink:"/docs/0.16.0/ast-builder/functions/text/padding",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"Character Conversion",permalink:"/docs/0.16.0/ast-builder/functions/text/character-conversion"},next:{title:"Position and Indexing",permalink:"/docs/0.16.0/ast-builder/functions/text/position-and-indexing"}},d={},p=[{value:"lpad",id:"lpad",level:2},{value:"rpad",id:"rpad",level:2},{value:"Examples",id:"examples",level:2}],u={toc:p},c="wrapper";function s(e){let{components:n,...t}=e;return(0,a.yg)(c,(0,r.A)({},u,t,{components:n,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"padding"},"Padding"),(0,a.yg)("p",null,"The AST Builder API in GlueSQL allows you to execute lpad and rpad functions for text padding."),(0,a.yg)("h2",{id:"lpad"},"lpad"),(0,a.yg)("p",null,(0,a.yg)("inlineCode",{parentName:"p"},"lpad")," returns the string with leading space if the length of the string is less than the specified length."),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-rust"},"lpad<'a, T: Into>>(expr: T, len: usize, fill: Option) -> ExprNode<'a>\n")),(0,a.yg)("h2",{id:"rpad"},"rpad"),(0,a.yg)("p",null,(0,a.yg)("inlineCode",{parentName:"p"},"rpad")," returns the string with trailing space if the length of the string is less than the specified length."),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-rust"},"rpad<'a, T: Into>>(expr: T, len: usize, fill: Option) -> ExprNode<'a>\n")),(0,a.yg)("h2",{id:"examples"},"Examples"),(0,a.yg)("p",null,"In these examples, the LPAD and RPAD functions should return matching values."),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-rust"},'use {\n crate::*,\n gluesql_core::{\n ast_builder::{function as f, *},\n prelude::Value::{Null, Str},\n },\n};\n\ntest_case!(padding, {\n let glue = get_glue!();\n\n let actual = values(vec![\n vec![f::lpad("\'hello\'", 10, None), f::rpad("\'hello\'", 10, None)],\n vec![\n f::lpad("\'hello\'", 10, Some("\'ab\'".into())),\n f::rpad("\'hello\'", 10, Some("\'ab\'".into())),\n ],\n vec![f::lpad("\'hello\'", 3, None), f::rpad("\'hello\'", 3, None)],\n vec![\n f::lpad("\'hello\'", 3, Some("\'ab\'".into())),\n f::rpad("\'hello\'", 3, Some("\'ab\'".into())),\n ],\n vec![f::lpad("NULL", 5, None), f::rpad("NULL", 5, None)],\n ])\n .alias_as("Sub")\n .select()\n .project("column1 AS lpaded")\n .project("column2 AS rpaded")\n .execute(glue)\n .await;\n let expected = Ok(select_with_null!(\n lpaded | rpaded;\n Str(" hello".to_owned()) Str("hello ".to_owned());\n Str("ababahello".to_owned()) Str("helloababa".to_owned());\n Str("hel".to_owned()) Str("hel".to_owned());\n Str("hel".to_owned()) Str("hel".to_owned());\n Null Null\n ));\n assert_eq!(\n actual, expected,\n "lpad and rpad should pad the string with given length"\n );\n});\n')),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre"},"| lpaded | rpaded |\n| ------------ | ------------ |\n| ' hello' | 'hello ' |\n| 'ababahello' | 'helloababa' |\n| 'hel' | 'hel' |\n| 'hel' | 'hel' |\n| Null | Null |\n")))}s.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/078a6308.4d53bdee.js b/docs/0.16.0/assets/js/078a6308.4d53bdee.js new file mode 100644 index 00000000..abd62682 --- /dev/null +++ b/docs/0.16.0/assets/js/078a6308.4d53bdee.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[5732],{5680:(e,n,t)=>{t.d(n,{xA:()=>c,yg:()=>m});var r=t(6540);function l(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function a(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function i(e){for(var n=1;n=0||(l[t]=e[t]);return l}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(l[t]=e[t])}return l}var u=r.createContext({}),s=function(e){var n=r.useContext(u),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},c=function(e){var n=s(e.components);return r.createElement(u.Provider,{value:n},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},f=r.forwardRef((function(e,n){var t=e.components,l=e.mdxType,a=e.originalType,u=e.parentName,c=o(e,["components","mdxType","originalType","parentName"]),p=s(t),f=l,m=p["".concat(u,".").concat(f)]||p[f]||d[f]||a;return t?r.createElement(m,i(i({ref:n},c),{},{components:t})):r.createElement(m,i({ref:n},c))}));function m(e,n){var t=arguments,l=n&&n.mdxType;if("string"==typeof e||l){var a=t.length,i=new Array(a);i[0]=f;var o={};for(var u in n)hasOwnProperty.call(n,u)&&(o[u]=n[u]);o.originalType=e,o[p]="string"==typeof e?e:l,i[1]=o;for(var s=2;s{t.r(n),t.d(n,{assets:()=>u,contentTitle:()=>i,default:()=>d,frontMatter:()=>a,metadata:()=>o,toc:()=>s});var r=t(8168),l=(t(6540),t(5680));const a={},i="Null Handling",o={unversionedId:"ast-builder/functions/others/null-handling",id:"ast-builder/functions/others/null-handling",title:"Null Handling",description:"In some cases, you may need to handle NULL values in your database. GlueSQL provides a function called ifnull to handle these cases.",source:"@site/docs/ast-builder/functions/others/null-handling.md",sourceDirName:"ast-builder/functions/others",slug:"/ast-builder/functions/others/null-handling",permalink:"/docs/0.16.0/ast-builder/functions/others/null-handling",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"Point Creation",permalink:"/docs/0.16.0/ast-builder/functions/geometry/point-creation"},next:{title:"Type Conversion",permalink:"/docs/0.16.0/ast-builder/functions/others/type-conversion"}},u={},s=[{value:"IFNULL - ifnull",id:"ifnull---ifnull",level:2}],c={toc:s},p="wrapper";function d(e){let{components:n,...t}=e;return(0,l.yg)(p,(0,r.A)({},c,t,{components:n,mdxType:"MDXLayout"}),(0,l.yg)("h1",{id:"null-handling"},"Null Handling"),(0,l.yg)("p",null,"In some cases, you may need to handle ",(0,l.yg)("inlineCode",{parentName:"p"},"NULL")," values in your database. GlueSQL provides a function called ",(0,l.yg)("inlineCode",{parentName:"p"},"ifnull")," to handle these cases."),(0,l.yg)("h2",{id:"ifnull---ifnull"},"IFNULL - ifnull"),(0,l.yg)("p",null,"The ",(0,l.yg)("inlineCode",{parentName:"p"},"ifnull")," function checks if the first expression is ",(0,l.yg)("inlineCode",{parentName:"p"},"NULL"),", and if it is, it returns the value of the second expression. If the first expression is not ",(0,l.yg)("inlineCode",{parentName:"p"},"NULL"),", it returns the value of the first expression."),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Foo")\n .select()\n .project("id")\n .project(col("name").ifnull(text("isnull"))) // If the "name" column is NULL, replace it with "isnull"\n .execute(glue)\n .await;\n')),(0,l.yg)("p",null,'In the above example, if the "name" column is ',(0,l.yg)("inlineCode",{parentName:"p"},"NULL"),', "isnull" is returned. Otherwise, the value of the "name" column is returned.'),(0,l.yg)("p",null,"You can also use ",(0,l.yg)("inlineCode",{parentName:"p"},"ifnull")," with another column:"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Foo")\n .select()\n .project("id")\n .project(col("name").ifnull(col("nickname"))) // If the "name" column is NULL, replace it with the value from the "nickname" column\n .execute(glue)\n .await;\n')),(0,l.yg)("p",null,'In this example, if the "name" column is ',(0,l.yg)("inlineCode",{parentName:"p"},"NULL"),', the value from the "nickname" column is returned. If "name" is not ',(0,l.yg)("inlineCode",{parentName:"p"},"NULL"),', the value of the "name" column is returned.'),(0,l.yg)("p",null,"The ",(0,l.yg)("inlineCode",{parentName:"p"},"ifnull")," function can also be used without a table:"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = values(vec![\n vec![ast_builder::ifnull(text("HELLO"), text("WORLD"))], // If "HELLO" is NULL (it\'s not), return "WORLD". Otherwise, return "HELLO".\n vec![ast_builder::ifnull(null(), text("WORLD"))], // If NULL is NULL (it is), return "WORLD".\n])\n.execute(glue)\n.await;\n')),(0,l.yg)("p",null,'In the first case, "HELLO" is returned because it\'s not ',(0,l.yg)("inlineCode",{parentName:"p"},"NULL"),'. In the second case, "WORLD" is returned because the first value is ',(0,l.yg)("inlineCode",{parentName:"p"},"NULL"),"."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/0b621d16.b92732eb.js b/docs/0.16.0/assets/js/0b621d16.b92732eb.js new file mode 100644 index 00000000..44430a3b --- /dev/null +++ b/docs/0.16.0/assets/js/0b621d16.b92732eb.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[8059],{5680:(e,n,t)=>{t.d(n,{xA:()=>u,yg:()=>g});var a=t(6540);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function i(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function o(e){for(var n=1;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var s=a.createContext({}),c=function(e){var n=a.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):o(o({},n),e)),t},u=function(e){var n=c(e.components);return a.createElement(s.Provider,{value:n},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},y=a.forwardRef((function(e,n){var t=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=c(t),y=r,g=p["".concat(s,".").concat(y)]||p[y]||d[y]||i;return t?a.createElement(g,o(o({ref:n},u),{},{components:t})):a.createElement(g,o({ref:n},u))}));function g(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var i=t.length,o=new Array(i);o[0]=y;var l={};for(var s in n)hasOwnProperty.call(n,s)&&(l[s]=n[s]);l.originalType=e,l[p]="string"==typeof e?e:r,o[1]=l;for(var c=2;c{t.r(n),t.d(n,{assets:()=>s,contentTitle:()=>o,default:()=>d,frontMatter:()=>i,metadata:()=>l,toc:()=>c});var a=t(8168),r=(t(6540),t(5680));const i={sidebar_position:5},o="DECIMAL",l={unversionedId:"sql-syntax/data-types/decimal",id:"sql-syntax/data-types/decimal",title:"DECIMAL",description:"The DECIMAL data type in SQL is used to store exact numeric values, making it suitable for financial calculations and other operations requiring a high level of precision without round-off errors. In GlueSQL, the DECIMAL data type is implemented using a pure Rust library, providing a 96-bit integer number, a scaling factor for specifying the decimal fraction, and a 1-bit sign.",source:"@site/docs/sql-syntax/data-types/decimal.md",sourceDirName:"sql-syntax/data-types",slug:"/sql-syntax/data-types/decimal",permalink:"/docs/0.16.0/sql-syntax/data-types/decimal",draft:!1,tags:[],version:"current",sidebarPosition:5,frontMatter:{sidebar_position:5},sidebar:"autoSidebar",previous:{title:"TEXT",permalink:"/docs/0.16.0/sql-syntax/data-types/text"},next:{title:"DATE",permalink:"/docs/0.16.0/sql-syntax/data-types/date"}},s={},c=[{value:"Creating a table with a DECIMAL column",id:"creating-a-table-with-a-decimal-column",level:2},{value:"Inserting data into the DECIMAL column",id:"inserting-data-into-the-decimal-column",level:2},{value:"Querying data from the DECIMAL column",id:"querying-data-from-the-decimal-column",level:2},{value:"Truncating trailing zeros",id:"truncating-trailing-zeros",level:2},{value:"Conclusion",id:"conclusion",level:2}],u={toc:c},p="wrapper";function d(e){let{components:n,...t}=e;return(0,r.yg)(p,(0,a.A)({},u,t,{components:n,mdxType:"MDXLayout"}),(0,r.yg)("h1",{id:"decimal"},"DECIMAL"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"DECIMAL")," data type in SQL is used to store exact numeric values, making it suitable for financial calculations and other operations requiring a high level of precision without round-off errors. In GlueSQL, the DECIMAL data type is implemented using a pure Rust library, providing a 96-bit integer number, a scaling factor for specifying the decimal fraction, and a 1-bit sign."),(0,r.yg)("p",null,"Here's an example of how to create a table, insert data, and query data using the ",(0,r.yg)("inlineCode",{parentName:"p"},"DECIMAL")," data type:"),(0,r.yg)("h2",{id:"creating-a-table-with-a-decimal-column"},"Creating a table with a DECIMAL column"),(0,r.yg)("p",null,"To create a table with a DECIMAL column, use the following SQL syntax:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE financial_data (description TEXT, value DECIMAL);\n")),(0,r.yg)("h2",{id:"inserting-data-into-the-decimal-column"},"Inserting data into the DECIMAL column"),(0,r.yg)("p",null,"To insert data into the DECIMAL column, provide the exact numeric values:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO financial_data (description, value) VALUES\n ('Revenue', 15000.25),\n ('Expense', 12000.75),\n ('Profit', 2999.50);\n")),(0,r.yg)("h2",{id:"querying-data-from-the-decimal-column"},"Querying data from the DECIMAL column"),(0,r.yg)("p",null,"To query data from the DECIMAL column, use standard SQL syntax:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT description, value FROM financial_data;\n")),(0,r.yg)("p",null,"This query will return the following result:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre"},"description | value\n------------|---------\nRevenue | 15000.25\nExpense | 12000.75\nProfit | 2999.50\n")),(0,r.yg)("h2",{id:"truncating-trailing-zeros"},"Truncating trailing zeros"),(0,r.yg)("p",null,"In GlueSQL's DECIMAL implementation, trailing zeros are preserved in the binary representation and may be exposed when converting the value to a string. To truncate trailing zeros, you can use the ",(0,r.yg)("inlineCode",{parentName:"p"},"normalize")," or ",(0,r.yg)("inlineCode",{parentName:"p"},"round_dp")," functions in Rust."),(0,r.yg)("h2",{id:"conclusion"},"Conclusion"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"DECIMAL")," data type is crucial for handling precise numeric values in SQL databases, especially in financial calculations and other applications requiring high accuracy without round-off errors. By understanding the basics of the DECIMAL data type and its use cases, you can effectively use it in your database designs and operations, ensuring that your applications can manage exact numeric values with precision."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/0c18287f.2d4dde49.js b/docs/0.16.0/assets/js/0c18287f.2d4dde49.js new file mode 100644 index 00000000..79cd51ca --- /dev/null +++ b/docs/0.16.0/assets/js/0c18287f.2d4dde49.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[2758],{5680:(e,n,t)=>{t.d(n,{xA:()=>c,yg:()=>d});var a=t(6540);function l(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function r(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function p(e){for(var n=1;n=0||(l[t]=e[t]);return l}(e,n);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(l[t]=e[t])}return l}var i=a.createContext({}),s=function(e){var n=a.useContext(i),t=n;return e&&(t="function"==typeof e?e(n):p(p({},n),e)),t},c=function(e){var n=s(e.components);return a.createElement(i.Provider,{value:n},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},y=a.forwardRef((function(e,n){var t=e.components,l=e.mdxType,r=e.originalType,i=e.parentName,c=o(e,["components","mdxType","originalType","parentName"]),u=s(t),y=l,d=u["".concat(i,".").concat(y)]||u[y]||m[y]||r;return t?a.createElement(d,p(p({ref:n},c),{},{components:t})):a.createElement(d,p({ref:n},c))}));function d(e,n){var t=arguments,l=n&&n.mdxType;if("string"==typeof e||l){var r=t.length,p=new Array(r);p[0]=y;var o={};for(var i in n)hasOwnProperty.call(n,i)&&(o[i]=n[i]);o.originalType=e,o[u]="string"==typeof e?e:l,p[1]=o;for(var s=2;s{t.r(n),t.d(n,{assets:()=>i,contentTitle:()=>p,default:()=>m,frontMatter:()=>r,metadata:()=>o,toc:()=>s});var a=t(8168),l=(t(6540),t(5680));const r={},p="APPEND",o={unversionedId:"sql-syntax/functions/list-map/append",id:"sql-syntax/functions/list-map/append",title:"APPEND",description:"The APPEND function in SQL is used to append an element to a list.",source:"@site/docs/sql-syntax/functions/list-map/append.md",sourceDirName:"sql-syntax/functions/list-map",slug:"/sql-syntax/functions/list-map/append",permalink:"/docs/0.16.0/sql-syntax/functions/list-map/append",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"TO_TIMESTAMP",permalink:"/docs/0.16.0/sql-syntax/functions/datetime/to-timestamp"},next:{title:"CONCAT",permalink:"/docs/0.16.0/sql-syntax/functions/list-map/concat"}},i={},s=[{value:"Syntax",id:"syntax",level:2},{value:"Examples",id:"examples",level:2}],c={toc:s},u="wrapper";function m(e){let{components:n,...t}=e;return(0,l.yg)(u,(0,a.A)({},c,t,{components:n,mdxType:"MDXLayout"}),(0,l.yg)("h1",{id:"append"},"APPEND"),(0,l.yg)("p",null,"The ",(0,l.yg)("inlineCode",{parentName:"p"},"APPEND")," function in SQL is used to append an element to a list."),(0,l.yg)("h2",{id:"syntax"},"Syntax"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"APPEND(list, element)\n")),(0,l.yg)("ul",null,(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("inlineCode",{parentName:"li"},"list"),": The list to which you want to append the element."),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("inlineCode",{parentName:"li"},"element"),": The element that you want to append to the list.")),(0,l.yg)("h2",{id:"examples"},"Examples"),(0,l.yg)("p",null,"First, create a table named ",(0,l.yg)("inlineCode",{parentName:"p"},"Append")," with columns for the list, an integer element, and a text element:"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE Append (\n id INTEGER,\n items LIST,\n element INTEGER,\n element2 TEXT\n);\n")),(0,l.yg)("p",null,"Insert some data into the ",(0,l.yg)("inlineCode",{parentName:"p"},"Append")," table:"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO Append VALUES\n(1, '[1, 2, 3]', 4, 'Foo');\n")),(0,l.yg)("p",null,"Use the ",(0,l.yg)("inlineCode",{parentName:"p"},"APPEND")," function to append the integer element to the list:"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT APPEND(items, element) AS myappend FROM Append;\n")),(0,l.yg)("p",null,"Use the ",(0,l.yg)("inlineCode",{parentName:"p"},"APPEND")," function to append the text element to the list:"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT APPEND(items, element2) AS myappend FROM Append;\n")),(0,l.yg)("p",null,"The ",(0,l.yg)("inlineCode",{parentName:"p"},"APPEND")," function requires a list as the first parameter. If you try to use it with a non-list value, an error will occur:"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT APPEND(element, element2) AS myappend FROM Append;\n")),(0,l.yg)("p",null,"You can also use the ",(0,l.yg)("inlineCode",{parentName:"p"},"APPEND")," function when inserting data into a table. First, create a table named ",(0,l.yg)("inlineCode",{parentName:"p"},"Foo")," with a column for the list:"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE Foo (\n elements LIST\n);\n")),(0,l.yg)("p",null,"Then, insert data into the ",(0,l.yg)("inlineCode",{parentName:"p"},"Foo")," table using the ",(0,l.yg)("inlineCode",{parentName:"p"},"APPEND")," function:"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO Foo VALUES (APPEND(CAST('[1, 2, 3]' AS LIST), 4));\n")),(0,l.yg)("p",null,"Finally, retrieve the list from the ",(0,l.yg)("inlineCode",{parentName:"p"},"Foo")," table:"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT elements AS myappend FROM Foo;\n")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/0c94c658.a5f781c3.js b/docs/0.16.0/assets/js/0c94c658.a5f781c3.js new file mode 100644 index 00000000..cedf0164 --- /dev/null +++ b/docs/0.16.0/assets/js/0c94c658.a5f781c3.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[4887],{5680:(e,n,a)=>{a.d(n,{xA:()=>p,yg:()=>c});var t=a(6540);function l(e,n,a){return n in e?Object.defineProperty(e,n,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[n]=a,e}function r(e,n){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var t=Object.getOwnPropertySymbols(e);n&&(t=t.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),a.push.apply(a,t)}return a}function o(e){for(var n=1;n=0||(l[a]=e[a]);return l}(e,n);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(t=0;t=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(l[a]=e[a])}return l}var s=t.createContext({}),m=function(e){var n=t.useContext(s),a=n;return e&&(a="function"==typeof e?e(n):o(o({},n),e)),a},p=function(e){var n=m(e.components);return t.createElement(s.Provider,{value:n},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var n=e.children;return t.createElement(t.Fragment,{},n)}},y=t.forwardRef((function(e,n){var a=e.components,l=e.mdxType,r=e.originalType,s=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),d=m(a),y=l,c=d["".concat(s,".").concat(y)]||d[y]||u[y]||r;return a?t.createElement(c,o(o({ref:n},p),{},{components:a})):t.createElement(c,o({ref:n},p))}));function c(e,n){var a=arguments,l=n&&n.mdxType;if("string"==typeof e||l){var r=a.length,o=new Array(r);o[0]=y;var i={};for(var s in n)hasOwnProperty.call(n,s)&&(i[s]=n[s]);i.originalType=e,i[d]="string"==typeof e?e:l,o[1]=i;for(var m=2;m{a.r(n),a.d(n,{assets:()=>s,contentTitle:()=>o,default:()=>u,frontMatter:()=>r,metadata:()=>i,toc:()=>m});var t=a(8168),l=(a(6540),a(5680));const r={sidebar_position:5},o="ALTER TABLE",i={unversionedId:"sql-syntax/statements/data-definition/alter-table",id:"sql-syntax/statements/data-definition/alter-table",title:"ALTER TABLE",description:"The ALTER TABLE statement is an SQL command used to modify the structure of an existing table in a database. This operation is useful when you need to add, remove, or modify columns or constraints in a table. In this document, we'll explain the syntax and usage of the ALTER TABLE statement, including the RENAME, ADD COLUMN, and DROP COLUMN clauses.",source:"@site/docs/sql-syntax/statements/data-definition/alter-table.md",sourceDirName:"sql-syntax/statements/data-definition",slug:"/sql-syntax/statements/data-definition/alter-table",permalink:"/docs/0.16.0/sql-syntax/statements/data-definition/alter-table",draft:!1,tags:[],version:"current",sidebarPosition:5,frontMatter:{sidebar_position:5},sidebar:"autoSidebar",previous:{title:"DROP INDEX",permalink:"/docs/0.16.0/sql-syntax/statements/data-definition/drop-index"},next:{title:"INSERT",permalink:"/docs/0.16.0/sql-syntax/statements/data-manipulation/insert"}},s={},m=[{value:"Syntax",id:"syntax",level:2},{value:"RENAME",id:"rename",level:3},{value:"ADD COLUMN",id:"add-column",level:3},{value:"DROP COLUMN",id:"drop-column",level:3},{value:"Examples",id:"examples",level:2},{value:"Summary",id:"summary",level:2}],p={toc:m},d="wrapper";function u(e){let{components:n,...a}=e;return(0,l.yg)(d,(0,t.A)({},p,a,{components:n,mdxType:"MDXLayout"}),(0,l.yg)("h1",{id:"alter-table"},"ALTER TABLE"),(0,l.yg)("p",null,"The ",(0,l.yg)("inlineCode",{parentName:"p"},"ALTER TABLE")," statement is an SQL command used to modify the structure of an existing table in a database. This operation is useful when you need to add, remove, or modify columns or constraints in a table. In this document, we'll explain the syntax and usage of the ",(0,l.yg)("inlineCode",{parentName:"p"},"ALTER TABLE")," statement, including the ",(0,l.yg)("inlineCode",{parentName:"p"},"RENAME"),", ",(0,l.yg)("inlineCode",{parentName:"p"},"ADD COLUMN"),", and ",(0,l.yg)("inlineCode",{parentName:"p"},"DROP COLUMN")," clauses."),(0,l.yg)("h2",{id:"syntax"},"Syntax"),(0,l.yg)("p",null,"The basic syntax for the ",(0,l.yg)("inlineCode",{parentName:"p"},"ALTER TABLE")," statement is as follows:"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"ALTER TABLE table_name action;\n")),(0,l.yg)("ul",null,(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("inlineCode",{parentName:"li"},"table_name"),": The name of the table you want to alter."),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("inlineCode",{parentName:"li"},"action"),": The action you want to perform on the table, such as renaming the table, adding a new column, or dropping an existing column.")),(0,l.yg)("h3",{id:"rename"},"RENAME"),(0,l.yg)("p",null,"To rename a table or a column, use the following syntax:"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"ALTER TABLE table_name RENAME [TO new_table_name | COLUMN column_name TO new_column_name];\n")),(0,l.yg)("h3",{id:"add-column"},"ADD COLUMN"),(0,l.yg)("p",null,"To add a new column to a table, use the following syntax:"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"ALTER TABLE table_name ADD COLUMN column_name datatype [DEFAULT default_value] [NOT NULL] [UNIQUE];\n")),(0,l.yg)("h3",{id:"drop-column"},"DROP COLUMN"),(0,l.yg)("p",null,"To drop an existing column from a table, use the following syntax:"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"ALTER TABLE table_name DROP COLUMN column_name;\n")),(0,l.yg)("h2",{id:"examples"},"Examples"),(0,l.yg)("ol",null,(0,l.yg)("li",{parentName:"ol"},"Renaming a table:")),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"ALTER TABLE employees RENAME TO staff;\n")),(0,l.yg)("p",null,"This command will rename the ",(0,l.yg)("inlineCode",{parentName:"p"},"employees")," table to ",(0,l.yg)("inlineCode",{parentName:"p"},"staff"),"."),(0,l.yg)("ol",{start:2},(0,l.yg)("li",{parentName:"ol"},"Renaming a column:")),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"ALTER TABLE employees RENAME COLUMN first_name TO given_name;\n")),(0,l.yg)("p",null,"This command will rename the ",(0,l.yg)("inlineCode",{parentName:"p"},"first_name")," column to ",(0,l.yg)("inlineCode",{parentName:"p"},"given_name")," in the ",(0,l.yg)("inlineCode",{parentName:"p"},"employees")," table."),(0,l.yg)("ol",{start:3},(0,l.yg)("li",{parentName:"ol"},"Adding a new column:")),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"ALTER TABLE employees ADD COLUMN department TEXT;\n")),(0,l.yg)("p",null,"This command will add a new ",(0,l.yg)("inlineCode",{parentName:"p"},"department")," column with the ",(0,l.yg)("inlineCode",{parentName:"p"},"TEXT")," datatype to the ",(0,l.yg)("inlineCode",{parentName:"p"},"employees")," table."),(0,l.yg)("ol",{start:4},(0,l.yg)("li",{parentName:"ol"},"Adding a new column with a default value:")),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"ALTER TABLE employees ADD COLUMN active BOOLEAN DEFAULT true;\n")),(0,l.yg)("p",null,"This command will add a new ",(0,l.yg)("inlineCode",{parentName:"p"},"active")," column with the ",(0,l.yg)("inlineCode",{parentName:"p"},"BOOLEAN")," datatype and a default value of ",(0,l.yg)("inlineCode",{parentName:"p"},"true")," to the ",(0,l.yg)("inlineCode",{parentName:"p"},"employees")," table."),(0,l.yg)("ol",{start:5},(0,l.yg)("li",{parentName:"ol"},"Dropping a column:")),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"ALTER TABLE employees DROP COLUMN department;\n")),(0,l.yg)("p",null,"This command will remove the ",(0,l.yg)("inlineCode",{parentName:"p"},"department")," column from the ",(0,l.yg)("inlineCode",{parentName:"p"},"employees")," table."),(0,l.yg)("h2",{id:"summary"},"Summary"),(0,l.yg)("p",null,"The ",(0,l.yg)("inlineCode",{parentName:"p"},"ALTER TABLE")," statement is an essential SQL command that allows you to modify the structure of an existing table in a database. It supports renaming tables and columns, adding new columns with optional default values and constraints, and dropping existing columns. By understanding the ",(0,l.yg)("inlineCode",{parentName:"p"},"ALTER TABLE")," syntax, you can efficiently manage your database schema and make necessary changes to your tables as your data requirements evolve."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/0ea64360.3dae4181.js b/docs/0.16.0/assets/js/0ea64360.3dae4181.js new file mode 100644 index 00000000..5f24bcb5 --- /dev/null +++ b/docs/0.16.0/assets/js/0ea64360.3dae4181.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[7814],{5680:(e,n,t)=>{t.d(n,{xA:()=>c,yg:()=>y});var a=t(6540);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function i(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function l(e){for(var n=1;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var s=a.createContext({}),u=function(e){var n=a.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):l(l({},n),e)),t},c=function(e){var n=u(e.components);return a.createElement(s.Provider,{value:n},e.children)},d="mdxType",g={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},p=a.forwardRef((function(e,n){var t=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,c=o(e,["components","mdxType","originalType","parentName"]),d=u(t),p=r,y=d["".concat(s,".").concat(p)]||d[p]||g[p]||i;return t?a.createElement(y,l(l({ref:n},c),{},{components:t})):a.createElement(y,l({ref:n},c))}));function y(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var i=t.length,l=new Array(i);l[0]=p;var o={};for(var s in n)hasOwnProperty.call(n,s)&&(o[s]=n[s]);o.originalType=e,o[d]="string"==typeof e?e:r,l[1]=o;for(var u=2;u{t.r(n),t.d(n,{assets:()=>s,contentTitle:()=>l,default:()=>g,frontMatter:()=>i,metadata:()=>o,toc:()=>u});var a=t(8168),r=(t(6540),t(5680));const i={},l="GENERATE_UUID",o={unversionedId:"sql-syntax/functions/others/generate-uuid",id:"sql-syntax/functions/others/generate-uuid",title:"GENERATE_UUID",description:"The GENERATE_UUID function is an SQL function provided by GlueSQL that generates a new UUID (Universally Unique Identifier) using the version 4 UUID algorithm. A UUID is a 128-bit value used to uniquely identify items in various computing systems. Version 4 UUIDs are randomly generated and have 122 bits of randomness, which ensures a very low probability of collisions.",source:"@site/docs/sql-syntax/functions/others/generate-uuid.md",sourceDirName:"sql-syntax/functions/others",slug:"/sql-syntax/functions/others/generate-uuid",permalink:"/docs/0.16.0/sql-syntax/functions/others/generate-uuid",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"CAST",permalink:"/docs/0.16.0/sql-syntax/functions/others/cast"},next:{title:"IFNULL",permalink:"/docs/0.16.0/sql-syntax/functions/others/ifnull"}},s={},u=[{value:"Syntax",id:"syntax",level:2},{value:"Usage",id:"usage",level:2},{value:"Creating a table with a UUID column",id:"creating-a-table-with-a-uuid-column",level:3},{value:"Inserting data with a UUID column",id:"inserting-data-with-a-uuid-column",level:3},{value:"Selecting data with a UUID column",id:"selecting-data-with-a-uuid-column",level:3},{value:"Error Handling",id:"error-handling",level:2}],c={toc:u},d="wrapper";function g(e){let{components:n,...t}=e;return(0,r.yg)(d,(0,a.A)({},c,t,{components:n,mdxType:"MDXLayout"}),(0,r.yg)("h1",{id:"generate_uuid"},"GENERATE_UUID"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"GENERATE_UUID")," function is an SQL function provided by GlueSQL that generates a new UUID (Universally Unique Identifier) using the version 4 UUID algorithm. A UUID is a 128-bit value used to uniquely identify items in various computing systems. Version 4 UUIDs are randomly generated and have 122 bits of randomness, which ensures a very low probability of collisions."),(0,r.yg)("h2",{id:"syntax"},"Syntax"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"GENERATE_UUID()\n")),(0,r.yg)("h2",{id:"usage"},"Usage"),(0,r.yg)("h3",{id:"creating-a-table-with-a-uuid-column"},"Creating a table with a UUID column"),(0,r.yg)("p",null,"You can use the ",(0,r.yg)("inlineCode",{parentName:"p"},"GENERATE_UUID")," function as the default value for a UUID column in a table."),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE SingleItem (id UUID DEFAULT GENERATE_UUID());\n")),(0,r.yg)("p",null,"This SQL statement creates a table called ",(0,r.yg)("inlineCode",{parentName:"p"},"SingleItem")," with a column named ",(0,r.yg)("inlineCode",{parentName:"p"},"id")," of data type ",(0,r.yg)("inlineCode",{parentName:"p"},"UUID"),". The default value for the ",(0,r.yg)("inlineCode",{parentName:"p"},"id")," column is generated using the ",(0,r.yg)("inlineCode",{parentName:"p"},"GENERATE_UUID")," function."),(0,r.yg)("h3",{id:"inserting-data-with-a-uuid-column"},"Inserting data with a UUID column"),(0,r.yg)("p",null,"You can also use the ",(0,r.yg)("inlineCode",{parentName:"p"},"GENERATE_UUID")," function directly when inserting data into a table."),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO SingleItem VALUES (GENERATE_UUID());\n")),(0,r.yg)("p",null,"This SQL statement inserts a new row into the ",(0,r.yg)("inlineCode",{parentName:"p"},"SingleItem")," table with a UUID value generated using the ",(0,r.yg)("inlineCode",{parentName:"p"},"GENERATE_UUID")," function."),(0,r.yg)("h3",{id:"selecting-data-with-a-uuid-column"},"Selecting data with a UUID column"),(0,r.yg)("p",null,"You can use the ",(0,r.yg)("inlineCode",{parentName:"p"},"GENERATE_UUID")," function in a SELECT statement to generate UUIDs on the fly."),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT GENERATE_UUID() as uuid FROM SingleItem;\n")),(0,r.yg)("p",null,"This SQL statement selects a new UUID for each row in the ",(0,r.yg)("inlineCode",{parentName:"p"},"SingleItem")," table."),(0,r.yg)("h2",{id:"error-handling"},"Error Handling"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"GENERATE_UUID")," function does not accept any arguments. If you provide any arguments to the function, an error will be raised."),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT generate_uuid(0) as uuid FROM SingleItem;\n")),(0,r.yg)("p",null,"This SQL statement will result in an error, as the ",(0,r.yg)("inlineCode",{parentName:"p"},"GENERATE_UUID")," function does not accept any arguments."))}g.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/104749c9.09fc621f.js b/docs/0.16.0/assets/js/104749c9.09fc621f.js new file mode 100644 index 00000000..bcf656d9 --- /dev/null +++ b/docs/0.16.0/assets/js/104749c9.09fc621f.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[7662],{9543:e=>{e.exports=JSON.parse('{"permalink":"/docs/0.16.0/blog/tags/release-note","page":1,"postsPerPage":10,"totalPages":1,"totalCount":2,"blogDescription":"Blog","blogTitle":"Blog"}')}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/107910e9.5dfe754c.js b/docs/0.16.0/assets/js/107910e9.5dfe754c.js new file mode 100644 index 00000000..d24c1f30 --- /dev/null +++ b/docs/0.16.0/assets/js/107910e9.5dfe754c.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[7637],{2879:s=>{s.exports=JSON.parse('{"label":"Test-Driven-Documentation","permalink":"/docs/0.16.0/blog/tags/test-driven-documentation","allTagsPath":"/docs/0.16.0/blog/tags","count":1}')}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/15868c40.654d0d37.js b/docs/0.16.0/assets/js/15868c40.654d0d37.js new file mode 100644 index 00000000..c1a72cff --- /dev/null +++ b/docs/0.16.0/assets/js/15868c40.654d0d37.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[6528],{5680:(e,n,t)=>{t.d(n,{xA:()=>p,yg:()=>y});var r=t(6540);function i(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function o(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function a(e){for(var n=1;n=0||(i[t]=e[t]);return i}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(i[t]=e[t])}return i}var l=r.createContext({}),u=function(e){var n=r.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):a(a({},n),e)),t},p=function(e){var n=u(e.components);return r.createElement(l.Provider,{value:n},e.children)},c="mdxType",f={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},g=r.forwardRef((function(e,n){var t=e.components,i=e.mdxType,o=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),c=u(t),g=i,y=c["".concat(l,".").concat(g)]||c[g]||f[g]||o;return t?r.createElement(y,a(a({ref:n},p),{},{components:t})):r.createElement(y,a({ref:n},p))}));function y(e,n){var t=arguments,i=n&&n.mdxType;if("string"==typeof e||i){var o=t.length,a=new Array(o);a[0]=g;var s={};for(var l in n)hasOwnProperty.call(n,l)&&(s[l]=n[l]);s.originalType=e,s[c]="string"==typeof e?e:i,a[1]=s;for(var u=2;u{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>a,default:()=>f,frontMatter:()=>o,metadata:()=>s,toc:()=>u});var r=t(8168),i=(t(6540),t(5680));const o={},a="POSITION",s={unversionedId:"sql-syntax/functions/text/position",id:"sql-syntax/functions/text/position",title:"POSITION",description:"The POSITION function in SQL is used to find the position of a substring in a string. The position of the first occurrence of the substring is returned. If the substring is not found, this function returns 0.",source:"@site/docs/sql-syntax/functions/text/position.md",sourceDirName:"sql-syntax/functions/text",slug:"/sql-syntax/functions/text/position",permalink:"/docs/0.16.0/sql-syntax/functions/text/position",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"LTRIM",permalink:"/docs/0.16.0/sql-syntax/functions/text/ltrim"},next:{title:"REPEAT",permalink:"/docs/0.16.0/sql-syntax/functions/text/repeat"}},l={},u=[{value:"Syntax",id:"syntax",level:2},{value:"Parameters",id:"parameters",level:2},{value:"Return Value",id:"return-value",level:2},{value:"Errors",id:"errors",level:2},{value:"Examples",id:"examples",level:2}],p={toc:u},c="wrapper";function f(e){let{components:n,...t}=e;return(0,i.yg)(c,(0,r.A)({},p,t,{components:n,mdxType:"MDXLayout"}),(0,i.yg)("h1",{id:"position"},"POSITION"),(0,i.yg)("p",null,"The ",(0,i.yg)("inlineCode",{parentName:"p"},"POSITION")," function in SQL is used to find the position of a substring in a string. The position of the first occurrence of the substring is returned. If the substring is not found, this function returns 0."),(0,i.yg)("h2",{id:"syntax"},"Syntax"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-sql"},"POSITION(substring IN string)\n")),(0,i.yg)("h2",{id:"parameters"},"Parameters"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("inlineCode",{parentName:"li"},"substring"),": The substring to search for."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("inlineCode",{parentName:"li"},"string"),": The string in which to search.")),(0,i.yg)("h2",{id:"return-value"},"Return Value"),(0,i.yg)("p",null,"The function returns an integer representing the position of the first occurrence of the substring in the string, starting from 1. If the substring is not found, the function returns 0."),(0,i.yg)("h2",{id:"errors"},"Errors"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},"If either ",(0,i.yg)("inlineCode",{parentName:"li"},"substring")," or ",(0,i.yg)("inlineCode",{parentName:"li"},"string")," are not string values, a ",(0,i.yg)("inlineCode",{parentName:"li"},"ValueError::NonStringParameterInPosition")," error will be returned.")),(0,i.yg)("h2",{id:"examples"},"Examples"),(0,i.yg)("p",null,"Consider a table ",(0,i.yg)("inlineCode",{parentName:"p"},"Food")," created and filled with the following data:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE Food (\n name TEXT\n);\nINSERT INTO Food VALUES ('pork');\nINSERT INTO Food VALUES ('burger');\n")),(0,i.yg)("p",null,"You can use the ",(0,i.yg)("inlineCode",{parentName:"p"},"POSITION")," function to find the position of a substring within the ",(0,i.yg)("inlineCode",{parentName:"p"},"name")," values:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT POSITION('e' IN name) AS test FROM Food;\n")),(0,i.yg)("p",null,"This will return:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre"},"0\n5\n")),(0,i.yg)("p",null,"The first 'e' in 'burger' is at position 5, so the function returns 5 for 'burger'. There is no 'e' in 'pork', so the function returns 0 for 'pork'."))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/160faf1d.05a9000e.js b/docs/0.16.0/assets/js/160faf1d.05a9000e.js new file mode 100644 index 00000000..cf9bcba4 --- /dev/null +++ b/docs/0.16.0/assets/js/160faf1d.05a9000e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[2570],{5680:(e,n,a)=>{a.d(n,{xA:()=>g,yg:()=>d});var r=a(6540);function t(e,n,a){return n in e?Object.defineProperty(e,n,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[n]=a,e}function l(e,n){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),a.push.apply(a,r)}return a}function i(e){for(var n=1;n=0||(t[a]=e[a]);return t}(e,n);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(t[a]=e[a])}return t}var u=r.createContext({}),o=function(e){var n=r.useContext(u),a=n;return e&&(a="function"==typeof e?e(n):i(i({},n),e)),a},g=function(e){var n=o(e.components);return r.createElement(u.Provider,{value:n},e.children)},p="mdxType",m={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},c=r.forwardRef((function(e,n){var a=e.components,t=e.mdxType,l=e.originalType,u=e.parentName,g=s(e,["components","mdxType","originalType","parentName"]),p=o(a),c=t,d=p["".concat(u,".").concat(c)]||p[c]||m[c]||l;return a?r.createElement(d,i(i({ref:n},g),{},{components:a})):r.createElement(d,i({ref:n},g))}));function d(e,n){var a=arguments,t=n&&n.mdxType;if("string"==typeof e||t){var l=a.length,i=new Array(l);i[0]=c;var s={};for(var u in n)hasOwnProperty.call(n,u)&&(s[u]=n[u]);s.originalType=e,s[p]="string"==typeof e?e:t,i[1]=s;for(var o=2;o{a.r(n),a.d(n,{assets:()=>u,contentTitle:()=>i,default:()=>m,frontMatter:()=>l,metadata:()=>s,toc:()=>o});var r=a(8168),t=(a(6540),a(5680));const l={},i="RADIANS",s={unversionedId:"sql-syntax/functions/math/radians",id:"sql-syntax/functions/math/radians",title:"RADIANS",description:"The RADIANS function is used to convert a given angle value from degrees to radians. It takes a single numeric argument (angle in degrees) and returns the angle in radians.",source:"@site/docs/sql-syntax/functions/math/radians.md",sourceDirName:"sql-syntax/functions/math",slug:"/sql-syntax/functions/math/radians",permalink:"/docs/0.16.0/sql-syntax/functions/math/radians",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"POWER",permalink:"/docs/0.16.0/sql-syntax/functions/math/power"},next:{title:"RAND",permalink:"/docs/0.16.0/sql-syntax/functions/math/rand"}},u={},o=[{value:"Syntax",id:"syntax",level:2},{value:"Examples",id:"examples",level:2},{value:"Example 1: Using RADIANS with float values",id:"example-1-using-radians-with-float-values",level:3},{value:"Example 2: Using RADIANS with integer values",id:"example-2-using-radians-with-integer-values",level:3},{value:"Example 3: Using RADIANS with zero",id:"example-3-using-radians-with-zero",level:3},{value:"Errors",id:"errors",level:2},{value:"Example 4: Using RADIANS with non-numeric values",id:"example-4-using-radians-with-non-numeric-values",level:3},{value:"Example 5: Using RADIANS with multiple arguments",id:"example-5-using-radians-with-multiple-arguments",level:3}],g={toc:o},p="wrapper";function m(e){let{components:n,...a}=e;return(0,t.yg)(p,(0,r.A)({},g,a,{components:n,mdxType:"MDXLayout"}),(0,t.yg)("h1",{id:"radians"},"RADIANS"),(0,t.yg)("p",null,"The ",(0,t.yg)("inlineCode",{parentName:"p"},"RADIANS")," function is used to convert a given angle value from degrees to radians. It takes a single numeric argument (angle in degrees) and returns the angle in radians."),(0,t.yg)("h2",{id:"syntax"},"Syntax"),(0,t.yg)("pre",null,(0,t.yg)("code",{parentName:"pre",className:"language-sql"},"RADIANS(value)\n")),(0,t.yg)("ul",null,(0,t.yg)("li",{parentName:"ul"},(0,t.yg)("inlineCode",{parentName:"li"},"value"),": A numeric expression (angle in degrees) to be converted to radians.")),(0,t.yg)("h2",{id:"examples"},"Examples"),(0,t.yg)("p",null,"Let's consider a table named ",(0,t.yg)("inlineCode",{parentName:"p"},"SingleItem")," with the following schema:"),(0,t.yg)("pre",null,(0,t.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE SingleItem (id FLOAT);\n")),(0,t.yg)("p",null,"Insert a row into the ",(0,t.yg)("inlineCode",{parentName:"p"},"SingleItem")," table:"),(0,t.yg)("pre",null,(0,t.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO SingleItem VALUES (0);\n")),(0,t.yg)("h3",{id:"example-1-using-radians-with-float-values"},"Example 1: Using RADIANS with float values"),(0,t.yg)("pre",null,(0,t.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT\nRADIANS(180.0) as radians_1,\nRADIANS(360.0) as radians_2\nFROM SingleItem;\n")),(0,t.yg)("p",null,"Result:"),(0,t.yg)("pre",null,(0,t.yg)("code",{parentName:"pre"}," radians_1 | radians_2\n-------------+-------------\n 3.141593 | 6.283185\n")),(0,t.yg)("h3",{id:"example-2-using-radians-with-integer-values"},"Example 2: Using RADIANS with integer values"),(0,t.yg)("pre",null,(0,t.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT RADIANS(90) as radians_with_int FROM SingleItem;\n")),(0,t.yg)("p",null,"Result:"),(0,t.yg)("pre",null,(0,t.yg)("code",{parentName:"pre"},"radians_with_int\n-----------------\n 1.570796\n")),(0,t.yg)("h3",{id:"example-3-using-radians-with-zero"},"Example 3: Using RADIANS with zero"),(0,t.yg)("pre",null,(0,t.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT RADIANS(0) as radians_with_zero FROM SingleItem;\n")),(0,t.yg)("p",null,"Result:"),(0,t.yg)("pre",null,(0,t.yg)("code",{parentName:"pre"},"radians_with_zero\n------------------\n 0.0\n")),(0,t.yg)("h2",{id:"errors"},"Errors"),(0,t.yg)("p",null,"The ",(0,t.yg)("inlineCode",{parentName:"p"},"RADIANS")," function requires a numeric value as its argument. Using non-numeric values or more than one argument will result in an error."),(0,t.yg)("h3",{id:"example-4-using-radians-with-non-numeric-values"},"Example 4: Using RADIANS with non-numeric values"),(0,t.yg)("pre",null,(0,t.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT RADIANS('string') AS radians FROM SingleItem;\n")),(0,t.yg)("p",null,"Error: Function requires a numeric value."),(0,t.yg)("h3",{id:"example-5-using-radians-with-multiple-arguments"},"Example 5: Using RADIANS with multiple arguments"),(0,t.yg)("pre",null,(0,t.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT RADIANS(0, 0) as radians_arg2 FROM SingleItem;\n")),(0,t.yg)("p",null,"Error: Function expects 1 argument, but 2 were provided."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/16682cd3.e744db6a.js b/docs/0.16.0/assets/js/16682cd3.e744db6a.js new file mode 100644 index 00000000..7b984588 --- /dev/null +++ b/docs/0.16.0/assets/js/16682cd3.e744db6a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[5138],{9417:s=>{s.exports=JSON.parse('{"label":"Automation","permalink":"/docs/0.16.0/blog/tags/automation","allTagsPath":"/docs/0.16.0/blog/tags","count":1}')}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/16815c2a.9ebfe213.js b/docs/0.16.0/assets/js/16815c2a.9ebfe213.js new file mode 100644 index 00000000..9439ad29 --- /dev/null +++ b/docs/0.16.0/assets/js/16815c2a.9ebfe213.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[5380],{5680:(e,t,n)=>{n.d(t,{xA:()=>u,yg:()=>g});var r=n(6540);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var c=r.createContext({}),l=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},u=function(e){var t=l(e.components);return r.createElement(c.Provider,{value:t},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,i=e.mdxType,a=e.originalType,c=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),d=l(n),m=i,g=d["".concat(c,".").concat(m)]||d[m]||p[m]||a;return n?r.createElement(g,o(o({ref:t},u),{},{components:n})):r.createElement(g,o({ref:t},u))}));function g(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var a=n.length,o=new Array(a);o[0]=m;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[d]="string"==typeof e?e:i,o[1]=s;for(var l=2;l{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>p,frontMatter:()=>a,metadata:()=>s,toc:()=>l});var r=n(8168),i=(n(6540),n(5680));const a={},o="Data Sorting and Limiting",s={unversionedId:"ast-builder/statements/querying/data-sorting-and-limiting",id:"ast-builder/statements/querying/data-sorting-and-limiting",title:"Data Sorting and Limiting",description:"Todo",source:"@site/docs/ast-builder/statements/querying/data-sorting-and-limiting.md",sourceDirName:"ast-builder/statements/querying",slug:"/ast-builder/statements/querying/data-sorting-and-limiting",permalink:"/docs/0.16.0/ast-builder/statements/querying/data-sorting-and-limiting",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"Data Selection and Projection",permalink:"/docs/0.16.0/ast-builder/statements/querying/data-selection-and-projection"},next:{title:"Inserting Data",permalink:"/docs/0.16.0/ast-builder/statements/data-manipulation/inserting-data"}},c={},l=[{value:"Todo",id:"todo",level:2}],u={toc:l},d="wrapper";function p(e){let{components:t,...n}=e;return(0,i.yg)(d,(0,r.A)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,i.yg)("h1",{id:"data-sorting-and-limiting"},"Data Sorting and Limiting"),(0,i.yg)("h2",{id:"todo"},"Todo"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre"},"- ORDER_BY: Sorts the result set in ascending or descending order based on specified column(s).\n- LIMIT: Limits the number of rows returned in the result set.\n- OFFSET: Skips a specified number of rows in the result set.\n")))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/1774.e76e375b.js b/docs/0.16.0/assets/js/1774.e76e375b.js new file mode 100644 index 00000000..ba5e6916 --- /dev/null +++ b/docs/0.16.0/assets/js/1774.e76e375b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[1774],{1774:(e,t,n)=>{n.r(t),n.d(t,{default:()=>c});var a=n(6540),l=n(1312),o=n(1003),r=n(9408);function c(){return a.createElement(a.Fragment,null,a.createElement(o.be,{title:(0,l.T)({id:"theme.NotFound.title",message:"Page Not Found"})}),a.createElement(r.A,null,a.createElement("main",{className:"container margin-vert--xl"},a.createElement("div",{className:"row"},a.createElement("div",{className:"col col--6 col--offset-3"},a.createElement("h1",{className:"hero__title"},a.createElement(l.A,{id:"theme.NotFound.title",description:"The title of the 404 page"},"Page Not Found")),a.createElement("p",null,a.createElement(l.A,{id:"theme.NotFound.p1",description:"The first paragraph of the 404 page"},"We could not find what you were looking for.")),a.createElement("p",null,a.createElement(l.A,{id:"theme.NotFound.p2",description:"The 2nd paragraph of the 404 page"},"Please contact the owner of the site that linked you to the original URL and let them know their link is broken.")))))))}}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/17896441.25d2eecf.js b/docs/0.16.0/assets/js/17896441.25d2eecf.js new file mode 100644 index 00000000..7de4928e --- /dev/null +++ b/docs/0.16.0/assets/js/17896441.25d2eecf.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[8401],{5022:(e,t,n)=>{n.r(t),n.d(t,{default:()=>ie});var a=n(6540),l=n(1003),o=n(9532);const r=a.createContext(null);function s(e){let{children:t,content:n}=e;const l=function(e){return(0,a.useMemo)((()=>({metadata:e.metadata,frontMatter:e.frontMatter,assets:e.assets,contentTitle:e.contentTitle,toc:e.toc})),[e])}(n);return a.createElement(r.Provider,{value:l},t)}function c(){const e=(0,a.useContext)(r);if(null===e)throw new o.dV("DocProvider");return e}function i(){const{metadata:e,frontMatter:t,assets:n}=c();return a.createElement(l.be,{title:e.title,description:e.description,keywords:t.keywords,image:n.image??t.image})}var d=n(53),m=n(4581),u=n(8168),v=n(1312),b=n(9022);function p(e){const{previous:t,next:n}=e;return a.createElement("nav",{className:"pagination-nav docusaurus-mt-lg","aria-label":(0,v.T)({id:"theme.docs.paginator.navAriaLabel",message:"Docs pages",description:"The ARIA label for the docs pagination"})},t&&a.createElement(b.A,(0,u.A)({},t,{subLabel:a.createElement(v.A,{id:"theme.docs.paginator.previous",description:"The label used to navigate to the previous doc"},"Previous")})),n&&a.createElement(b.A,(0,u.A)({},n,{subLabel:a.createElement(v.A,{id:"theme.docs.paginator.next",description:"The label used to navigate to the next doc"},"Next"),isNext:!0})))}function h(){const{metadata:e}=c();return a.createElement(p,{previous:e.previous,next:e.next})}var f=n(4586),E=n(5489),g=n(4070),A=n(7559),L=n(5597),C=n(2252);const N={unreleased:function(e){let{siteTitle:t,versionMetadata:n}=e;return a.createElement(v.A,{id:"theme.docs.versions.unreleasedVersionLabel",description:"The label used to tell the user that he's browsing an unreleased doc version",values:{siteTitle:t,versionLabel:a.createElement("b",null,n.label)}},"This is unreleased documentation for {siteTitle} {versionLabel} version.")},unmaintained:function(e){let{siteTitle:t,versionMetadata:n}=e;return a.createElement(v.A,{id:"theme.docs.versions.unmaintainedVersionLabel",description:"The label used to tell the user that he's browsing an unmaintained doc version",values:{siteTitle:t,versionLabel:a.createElement("b",null,n.label)}},"This is documentation for {siteTitle} {versionLabel}, which is no longer actively maintained.")}};function _(e){const t=N[e.versionMetadata.banner];return a.createElement(t,e)}function x(e){let{versionLabel:t,to:n,onClick:l}=e;return a.createElement(v.A,{id:"theme.docs.versions.latestVersionSuggestionLabel",description:"The label used to tell the user to check the latest version",values:{versionLabel:t,latestVersionLink:a.createElement("b",null,a.createElement(E.A,{to:n,onClick:l},a.createElement(v.A,{id:"theme.docs.versions.latestVersionLinkLabel",description:"The label used for the latest version suggestion link label"},"latest version")))}},"For up-to-date documentation, see the {latestVersionLink} ({versionLabel}).")}function T(e){let{className:t,versionMetadata:n}=e;const{siteConfig:{title:l}}=(0,f.A)(),{pluginId:o}=(0,g.vT)({failfast:!0}),{savePreferredVersionName:r}=(0,L.g1)(o),{latestDocSuggestion:s,latestVersionSuggestion:c}=(0,g.HW)(o),i=s??(m=c).docs.find((e=>e.id===m.mainDocId));var m;return a.createElement("div",{className:(0,d.A)(t,A.G.docs.docVersionBanner,"alert alert--warning margin-bottom--md"),role:"alert"},a.createElement("div",null,a.createElement(_,{siteTitle:l,versionMetadata:n})),a.createElement("div",{className:"margin-top--md"},a.createElement(x,{versionLabel:c.label,to:i.path,onClick:()=>r(c.name)})))}function k(e){let{className:t}=e;const n=(0,C.r)();return n.banner?a.createElement(T,{className:t,versionMetadata:n}):null}function H(e){let{className:t}=e;const n=(0,C.r)();return n.badge?a.createElement("span",{className:(0,d.A)(t,A.G.docs.docVersionBadge,"badge badge--secondary")},a.createElement(v.A,{id:"theme.docs.versionBadge.label",values:{versionLabel:n.label}},"Version: {versionLabel}")):null}function U(e){let{lastUpdatedAt:t,formattedLastUpdatedAt:n}=e;return a.createElement(v.A,{id:"theme.lastUpdated.atDate",description:"The words used to describe on which date a page has been last updated",values:{date:a.createElement("b",null,a.createElement("time",{dateTime:new Date(1e3*t).toISOString()},n))}}," on {date}")}function y(e){let{lastUpdatedBy:t}=e;return a.createElement(v.A,{id:"theme.lastUpdated.byUser",description:"The words used to describe by who the page has been last updated",values:{user:a.createElement("b",null,t)}}," by {user}")}function w(e){let{lastUpdatedAt:t,formattedLastUpdatedAt:n,lastUpdatedBy:l}=e;return a.createElement("span",{className:A.G.common.lastUpdated},a.createElement(v.A,{id:"theme.lastUpdated.lastUpdatedAtBy",description:"The sentence used to display when a page has been last updated, and by who",values:{atDate:t&&n?a.createElement(U,{lastUpdatedAt:t,formattedLastUpdatedAt:n}):"",byUser:l?a.createElement(y,{lastUpdatedBy:l}):""}},"Last updated{atDate}{byUser}"),!1)}var M=n(1943),I=n(2053);const B={lastUpdated:"lastUpdated_vwxv"};function O(e){return a.createElement("div",{className:(0,d.A)(A.G.docs.docFooterTagsRow,"row margin-bottom--sm")},a.createElement("div",{className:"col"},a.createElement(I.A,e)))}function V(e){let{editUrl:t,lastUpdatedAt:n,lastUpdatedBy:l,formattedLastUpdatedAt:o}=e;return a.createElement("div",{className:(0,d.A)(A.G.docs.docFooterEditMetaRow,"row")},a.createElement("div",{className:"col"},t&&a.createElement(M.A,{editUrl:t})),a.createElement("div",{className:(0,d.A)("col",B.lastUpdated)},(n||l)&&a.createElement(w,{lastUpdatedAt:n,formattedLastUpdatedAt:o,lastUpdatedBy:l})))}function P(){const{metadata:e}=c(),{editUrl:t,lastUpdatedAt:n,formattedLastUpdatedAt:l,lastUpdatedBy:o,tags:r}=e,s=r.length>0,i=!!(t||n||o);return s||i?a.createElement("footer",{className:(0,d.A)(A.G.docs.docFooter,"docusaurus-mt-lg")},s&&a.createElement(O,{tags:r}),i&&a.createElement(V,{editUrl:t,lastUpdatedAt:n,lastUpdatedBy:o,formattedLastUpdatedAt:l})):null}var S=n(1422),D=n(5195);const G={tocCollapsibleButton:"tocCollapsibleButton_TO0P",tocCollapsibleButtonExpanded:"tocCollapsibleButtonExpanded_MG3E"};function R(e){let{collapsed:t,...n}=e;return a.createElement("button",(0,u.A)({type:"button"},n,{className:(0,d.A)("clean-btn",G.tocCollapsibleButton,!t&&G.tocCollapsibleButtonExpanded,n.className)}),a.createElement(v.A,{id:"theme.TOCCollapsible.toggleButtonLabel",description:"The label used by the button on the collapsible TOC component"},"On this page"))}const F={tocCollapsible:"tocCollapsible_ETCw",tocCollapsibleContent:"tocCollapsibleContent_vkbj",tocCollapsibleExpanded:"tocCollapsibleExpanded_sAul"};function z(e){let{toc:t,className:n,minHeadingLevel:l,maxHeadingLevel:o}=e;const{collapsed:r,toggleCollapsed:s}=(0,S.u)({initialState:!0});return a.createElement("div",{className:(0,d.A)(F.tocCollapsible,!r&&F.tocCollapsibleExpanded,n)},a.createElement(R,{collapsed:r,onClick:s}),a.createElement(S.N,{lazy:!0,className:F.tocCollapsibleContent,collapsed:r},a.createElement(D.A,{toc:t,minHeadingLevel:l,maxHeadingLevel:o})))}const j={tocMobile:"tocMobile_ITEo"};function q(){const{toc:e,frontMatter:t}=c();return a.createElement(z,{toc:e,minHeadingLevel:t.toc_min_heading_level,maxHeadingLevel:t.toc_max_heading_level,className:(0,d.A)(A.G.docs.docTocMobile,j.tocMobile)})}var $=n(7763);function W(){const{toc:e,frontMatter:t}=c();return a.createElement($.A,{toc:e,minHeadingLevel:t.toc_min_heading_level,maxHeadingLevel:t.toc_max_heading_level,className:A.G.docs.docTocDesktop})}var Y=n(1107),Z=n(7780);function J(e){let{children:t}=e;const n=function(){const{metadata:e,frontMatter:t,contentTitle:n}=c();return t.hide_title||void 0!==n?null:e.title}();return a.createElement("div",{className:(0,d.A)(A.G.docs.docMarkdown,"markdown")},n&&a.createElement("header",null,a.createElement(Y.A,{as:"h1"},n)),a.createElement(Z.A,null,t))}var K=n(1754),Q=n(9169),X=n(6025);function ee(e){return a.createElement("svg",(0,u.A)({viewBox:"0 0 24 24"},e),a.createElement("path",{d:"M10 19v-5h4v5c0 .55.45 1 1 1h3c.55 0 1-.45 1-1v-7h1.7c.46 0 .68-.57.33-.87L12.67 3.6c-.38-.34-.96-.34-1.34 0l-8.36 7.53c-.34.3-.13.87.33.87H5v7c0 .55.45 1 1 1h3c.55 0 1-.45 1-1z",fill:"currentColor"}))}const te={breadcrumbHomeIcon:"breadcrumbHomeIcon_YNFT"};function ne(){const e=(0,X.A)("/");return a.createElement("li",{className:"breadcrumbs__item"},a.createElement(E.A,{"aria-label":(0,v.T)({id:"theme.docs.breadcrumbs.home",message:"Home page",description:"The ARIA label for the home page in the breadcrumbs"}),className:"breadcrumbs__link",href:e},a.createElement(ee,{className:te.breadcrumbHomeIcon})))}const ae={breadcrumbsContainer:"breadcrumbsContainer_Z_bl"};function le(e){let{children:t,href:n,isLast:l}=e;const o="breadcrumbs__link";return l?a.createElement("span",{className:o,itemProp:"name"},t):n?a.createElement(E.A,{className:o,href:n,itemProp:"item"},a.createElement("span",{itemProp:"name"},t)):a.createElement("span",{className:o},t)}function oe(e){let{children:t,active:n,index:l,addMicrodata:o}=e;return a.createElement("li",(0,u.A)({},o&&{itemScope:!0,itemProp:"itemListElement",itemType:"https://schema.org/ListItem"},{className:(0,d.A)("breadcrumbs__item",{"breadcrumbs__item--active":n})}),t,a.createElement("meta",{itemProp:"position",content:String(l+1)}))}function re(){const e=(0,K.OF)(),t=(0,Q.Dt)();return e?a.createElement("nav",{className:(0,d.A)(A.G.docs.docBreadcrumbs,ae.breadcrumbsContainer),"aria-label":(0,v.T)({id:"theme.docs.breadcrumbs.navAriaLabel",message:"Breadcrumbs",description:"The ARIA label for the breadcrumbs"})},a.createElement("ul",{className:"breadcrumbs",itemScope:!0,itemType:"https://schema.org/BreadcrumbList"},t&&a.createElement(ne,null),e.map(((t,n)=>{const l=n===e.length-1;return a.createElement(oe,{key:n,active:l,index:n,addMicrodata:!!t.href},a.createElement(le,{href:t.href,isLast:l},t.label))})))):null}const se={docItemContainer:"docItemContainer_Djhp",docItemCol:"docItemCol_VOVn"};function ce(e){let{children:t}=e;const n=function(){const{frontMatter:e,toc:t}=c(),n=(0,m.l)(),l=e.hide_table_of_contents,o=!l&&t.length>0;return{hidden:l,mobile:o?a.createElement(q,null):void 0,desktop:!o||"desktop"!==n&&"ssr"!==n?void 0:a.createElement(W,null)}}();return a.createElement("div",{className:"row"},a.createElement("div",{className:(0,d.A)("col",!n.hidden&&se.docItemCol)},a.createElement(k,null),a.createElement("div",{className:se.docItemContainer},a.createElement("article",null,a.createElement(re,null),a.createElement(H,null),n.mobile,a.createElement(J,null,t),a.createElement(P,null)),a.createElement(h,null))),n.desktop&&a.createElement("div",{className:"col col--3"},n.desktop))}function ie(e){const t=`docs-doc-id-${e.content.metadata.unversionedId}`,n=e.content;return a.createElement(s,{content:e.content},a.createElement(l.e3,{className:t},a.createElement(i,null),a.createElement(ce,null,a.createElement(n,null))))}},7763:(e,t,n)=>{n.d(t,{A:()=>d});var a=n(8168),l=n(6540),o=n(53),r=n(5195);const s={tableOfContents:"tableOfContents_bqdL",docItemContainer:"docItemContainer_F8PC"},c="table-of-contents__link toc-highlight",i="table-of-contents__link--active";function d(e){let{className:t,...n}=e;return l.createElement("div",{className:(0,o.A)(s.tableOfContents,"thin-scrollbar",t)},l.createElement(r.A,(0,a.A)({},n,{linkClassName:c,linkActiveClassName:i})))}},5195:(e,t,n)=>{n.d(t,{A:()=>b});var a=n(8168),l=n(6540),o=n(6342);function r(e){const t=e.map((e=>({...e,parentIndex:-1,children:[]}))),n=Array(7).fill(-1);t.forEach(((e,t)=>{const a=n.slice(2,e.level);e.parentIndex=Math.max(...a),n[e.level]=t}));const a=[];return t.forEach((e=>{const{parentIndex:n,...l}=e;n>=0?t[n].children.push(l):a.push(l)})),a}function s(e){let{toc:t,minHeadingLevel:n,maxHeadingLevel:a}=e;return t.flatMap((e=>{const t=s({toc:e.children,minHeadingLevel:n,maxHeadingLevel:a});return function(e){return e.level>=n&&e.level<=a}(e)?[{...e,children:t}]:t}))}function c(e){const t=e.getBoundingClientRect();return t.top===t.bottom?c(e.parentNode):t}function i(e,t){let{anchorTopOffset:n}=t;const a=e.find((e=>c(e).top>=n));if(a){return function(e){return e.top>0&&e.bottom{e.current=t?0:document.querySelector(".navbar").clientHeight}),[t]),e}function m(e){const t=(0,l.useRef)(void 0),n=d();(0,l.useEffect)((()=>{if(!e)return()=>{};const{linkClassName:a,linkActiveClassName:l,minHeadingLevel:o,maxHeadingLevel:r}=e;function s(){const e=function(e){return Array.from(document.getElementsByClassName(e))}(a),s=function(e){let{minHeadingLevel:t,maxHeadingLevel:n}=e;const a=[];for(let l=t;l<=n;l+=1)a.push(`h${l}.anchor`);return Array.from(document.querySelectorAll(a.join()))}({minHeadingLevel:o,maxHeadingLevel:r}),c=i(s,{anchorTopOffset:n.current}),d=e.find((e=>c&&c.id===function(e){return decodeURIComponent(e.href.substring(e.href.indexOf("#")+1))}(e)));e.forEach((e=>{!function(e,n){n?(t.current&&t.current!==e&&t.current.classList.remove(l),e.classList.add(l),t.current=e):e.classList.remove(l)}(e,e===d)}))}return document.addEventListener("scroll",s),document.addEventListener("resize",s),s(),()=>{document.removeEventListener("scroll",s),document.removeEventListener("resize",s)}}),[e,n])}function u(e){let{toc:t,className:n,linkClassName:a,isChild:o}=e;return t.length?l.createElement("ul",{className:o?void 0:n},t.map((e=>l.createElement("li",{key:e.id},l.createElement("a",{href:`#${e.id}`,className:a??void 0,dangerouslySetInnerHTML:{__html:e.value}}),l.createElement(u,{isChild:!0,toc:e.children,className:n,linkClassName:a}))))):null}const v=l.memo(u);function b(e){let{toc:t,className:n="table-of-contents table-of-contents__left-border",linkClassName:c="table-of-contents__link",linkActiveClassName:i,minHeadingLevel:d,maxHeadingLevel:u,...b}=e;const p=(0,o.p)(),h=d??p.tableOfContents.minHeadingLevel,f=u??p.tableOfContents.maxHeadingLevel,E=function(e){let{toc:t,minHeadingLevel:n,maxHeadingLevel:a}=e;return(0,l.useMemo)((()=>s({toc:r(t),minHeadingLevel:n,maxHeadingLevel:a})),[t,n,a])}({toc:t,minHeadingLevel:h,maxHeadingLevel:f});return m((0,l.useMemo)((()=>{if(c&&i)return{linkClassName:c,linkActiveClassName:i,minHeadingLevel:h,maxHeadingLevel:f}}),[c,i,h,f])),l.createElement(v,(0,a.A)({toc:E,className:n,linkClassName:c},b))}},2252:(e,t,n)=>{n.d(t,{n:()=>r,r:()=>s});var a=n(6540),l=n(9532);const o=a.createContext(null);function r(e){let{children:t,version:n}=e;return a.createElement(o.Provider,{value:n},t)}function s(){const e=(0,a.useContext)(o);if(null===e)throw new l.dV("DocsVersionProvider");return e}}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/1798d0b3.36e85a04.js b/docs/0.16.0/assets/js/1798d0b3.36e85a04.js new file mode 100644 index 00000000..05c2f9b2 --- /dev/null +++ b/docs/0.16.0/assets/js/1798d0b3.36e85a04.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[6585],{5680:(e,t,a)=>{a.d(t,{xA:()=>y,yg:()=>g});var n=a(6540);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function o(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function i(e){for(var t=1;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var s=n.createContext({}),d=function(e){var t=n.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},y=function(e){var t=d(e.components);return n.createElement(s.Provider,{value:t},e.children)},c="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},p=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,o=e.originalType,s=e.parentName,y=l(e,["components","mdxType","originalType","parentName"]),c=d(a),p=r,g=c["".concat(s,".").concat(p)]||c[p]||u[p]||o;return a?n.createElement(g,i(i({ref:t},y),{},{components:a})):n.createElement(g,i({ref:t},y))}));function g(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=a.length,i=new Array(o);i[0]=p;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:r,i[1]=l;for(var d=2;d{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>u,frontMatter:()=>o,metadata:()=>l,toc:()=>d});var n=a(8168),r=(a(6540),a(5680));const o={},i="BYTEA",l={unversionedId:"sql-syntax/data-types/bytea",id:"sql-syntax/data-types/bytea",title:"BYTEA",description:"The BYTEA data type in SQL is used to store binary data, such as images, audio files, or any other type of data that needs to be stored in its raw form. In GlueSQL, the BYTEA data type is represented as a sequence of bytes.",source:"@site/docs/sql-syntax/data-types/bytea.md",sourceDirName:"sql-syntax/data-types",slug:"/sql-syntax/data-types/bytea",permalink:"/docs/0.16.0/sql-syntax/data-types/bytea",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"MAP",permalink:"/docs/0.16.0/sql-syntax/data-types/map"},next:{title:"INET",permalink:"/docs/0.16.0/sql-syntax/data-types/inet"}},s={},d=[{value:"Creating a table with a BYTEA column",id:"creating-a-table-with-a-bytea-column",level:2},{value:"Inserting data into the BYTEA column",id:"inserting-data-into-the-bytea-column",level:2},{value:"Querying data from the BYTEA column",id:"querying-data-from-the-bytea-column",level:2},{value:"Error handling",id:"error-handling",level:2},{value:"Conclusion",id:"conclusion",level:2}],y={toc:d},c="wrapper";function u(e){let{components:t,...a}=e;return(0,r.yg)(c,(0,n.A)({},y,a,{components:t,mdxType:"MDXLayout"}),(0,r.yg)("h1",{id:"bytea"},"BYTEA"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"BYTEA")," data type in SQL is used to store binary data, such as images, audio files, or any other type of data that needs to be stored in its raw form. In GlueSQL, the BYTEA data type is represented as a sequence of bytes."),(0,r.yg)("p",null,"Here's an example of how to create a table, insert data, and query data using the ",(0,r.yg)("inlineCode",{parentName:"p"},"BYTEA")," data type:"),(0,r.yg)("h2",{id:"creating-a-table-with-a-bytea-column"},"Creating a table with a BYTEA column"),(0,r.yg)("p",null,"To create a table with a BYTEA column, use the following SQL syntax:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE binary_data (data BYTEA);\n")),(0,r.yg)("h2",{id:"inserting-data-into-the-bytea-column"},"Inserting data into the BYTEA column"),(0,r.yg)("p",null,"To insert data into the BYTEA column, provide the binary data in hexadecimal format using the ",(0,r.yg)("inlineCode",{parentName:"p"},"X")," prefix:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO binary_data (data) VALUES\n (X'123456'),\n (X'ab0123'),\n (X'936DA0');\n")),(0,r.yg)("p",null,"Please note that the hexadecimal string must have an even number of characters, or an error will be thrown."),(0,r.yg)("h2",{id:"querying-data-from-the-bytea-column"},"Querying data from the BYTEA column"),(0,r.yg)("p",null,"To query data from the BYTEA column, use standard SQL syntax:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT data FROM binary_data;\n")),(0,r.yg)("p",null,"This query will return the following result:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre"},"data\n----------------\n123456\nab0123\n936DA0\n")),(0,r.yg)("h2",{id:"error-handling"},"Error handling"),(0,r.yg)("p",null,"When inserting data into the BYTEA column, you may encounter errors due to incompatible data types or incorrectly formatted hexadecimal strings. For example, inserting a regular integer or an odd-length hexadecimal string will result in an error:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO binary_data (data) VALUES (0);\n-- Error: Incompatible literal for data type BYTEA\n\nINSERT INTO binary_data (data) VALUES (X'123');\n-- Error: Failed to decode hexadecimal string\n")),(0,r.yg)("h2",{id:"conclusion"},"Conclusion"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"BYTEA")," data type is essential for storing binary data in SQL databases. By understanding the basics of the BYTEA data type and its use cases, you can effectively use it in your database designs and operations, ensuring that your applications can manage binary data efficiently and securely."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/194e858c.98c96ae7.js b/docs/0.16.0/assets/js/194e858c.98c96ae7.js new file mode 100644 index 00000000..495bd1fc --- /dev/null +++ b/docs/0.16.0/assets/js/194e858c.98c96ae7.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[4234],{5680:(e,t,n)=>{n.d(t,{xA:()=>p,yg:()=>y});var r=n(6540);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function s(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=r.createContext({}),m=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},p=function(e){var t=m(e.components);return r.createElement(l.Provider,{value:t},e.children)},c="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},u=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,l=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),c=m(n),u=a,y=c["".concat(l,".").concat(u)]||c[u]||d[u]||o;return n?r.createElement(y,s(s({ref:t},p),{},{components:n})):r.createElement(y,s({ref:t},p))}));function y(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,s=new Array(o);s[0]=u;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i[c]="string"==typeof e?e:a,s[1]=i;for(var m=2;m{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>s,default:()=>d,frontMatter:()=>o,metadata:()=>i,toc:()=>m});var r=n(8168),a=(n(6540),n(5680));const o={sidebar_position:3},s="AlterTable",i={unversionedId:"storages/developing-custom-storages/store-traits/alter-table",id:"storages/developing-custom-storages/store-traits/alter-table",title:"AlterTable",description:"The AlterTable trait corresponds to the SQL ALTER TABLE statement and is used for modifying existing schemas. It is not necessary to implement the AlterTable trait. If you are dealing with data that is difficult to modify schema-wise or schemaless data, there is no need to implement the AlterTable trait. It is an optional trait that custom storage developers can choose to implement.",source:"@site/docs/storages/developing-custom-storages/store-traits/alter-table.md",sourceDirName:"storages/developing-custom-storages/store-traits",slug:"/storages/developing-custom-storages/store-traits/alter-table",permalink:"/docs/0.16.0/storages/developing-custom-storages/store-traits/alter-table",draft:!1,tags:[],version:"current",sidebarPosition:3,frontMatter:{sidebar_position:3},sidebar:"autoSidebar",previous:{title:"StoreMut",permalink:"/docs/0.16.0/storages/developing-custom-storages/store-traits/store-mut"},next:{title:"Transaction",permalink:"/docs/0.16.0/storages/developing-custom-storages/store-traits/transaction"}},l={},m=[],p={toc:m},c="wrapper";function d(e){let{components:t,...n}=e;return(0,a.yg)(c,(0,r.A)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"altertable"},"AlterTable"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"AlterTable")," trait corresponds to the SQL ALTER TABLE statement and is used for modifying existing schemas. It is not necessary to implement the ",(0,a.yg)("inlineCode",{parentName:"p"},"AlterTable")," trait. If you are dealing with data that is difficult to modify schema-wise or schemaless data, there is no need to implement the ",(0,a.yg)("inlineCode",{parentName:"p"},"AlterTable")," trait. It is an optional trait that custom storage developers can choose to implement."),(0,a.yg)("p",null,"Similar to the ",(0,a.yg)("inlineCode",{parentName:"p"},"Store")," & ",(0,a.yg)("inlineCode",{parentName:"p"},"StoreMut")," combination, if you implement the ",(0,a.yg)("inlineCode",{parentName:"p"},"AlterTable")," trait, you can use additional tests in the Test Suite to verify your implementation. There are currently four types of methods supported by ",(0,a.yg)("inlineCode",{parentName:"p"},"AlterTable"),":"),(0,a.yg)("ol",null,(0,a.yg)("li",{parentName:"ol"},(0,a.yg)("p",{parentName:"li"},(0,a.yg)("inlineCode",{parentName:"p"},"rename_schema"),": Corresponds to the SQL statement ",(0,a.yg)("inlineCode",{parentName:"p"},"ALTER TABLE {table-name} RENAME TO {other-name};"),". This method renames a schema.")),(0,a.yg)("li",{parentName:"ol"},(0,a.yg)("p",{parentName:"li"},(0,a.yg)("inlineCode",{parentName:"p"},"rename_column"),": Corresponds to the SQL statement ",(0,a.yg)("inlineCode",{parentName:"p"},"ALTER TABLE {table-name} RENAME COLUMN {col1} TO {col2};"),". This method renames a column within a table.")),(0,a.yg)("li",{parentName:"ol"},(0,a.yg)("p",{parentName:"li"},(0,a.yg)("inlineCode",{parentName:"p"},"add_column"),": Corresponds to the SQL statement ",(0,a.yg)("inlineCode",{parentName:"p"},"ALTER TABLE {table-name} ADD COLUMN {col} {data-type} {constraints}"),". This method adds a new column to a table with specified data type and constraints.")),(0,a.yg)("li",{parentName:"ol"},(0,a.yg)("p",{parentName:"li"},(0,a.yg)("inlineCode",{parentName:"p"},"drop_column"),": Corresponds to the SQL statement ",(0,a.yg)("inlineCode",{parentName:"p"},"ALTER TABLE {table-name} DROP COLUMN {col}"),". This method removes a column from a table."))),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-rust"},"#[async_trait(?Send)]\npub trait AlterTable {\n async fn rename_schema(&mut self, _table_name: &str, _new_table_name: &str) -> Result<()>;\n\n async fn rename_column(&mut self,\n _table_name: &str,\n _old_column_name: &str,\n _new_column_name: &str,\n ) -> Result<()>;\n\n async fn add_column(&mut self, _table_name: &str, _column_def: &ColumnDef) -> Result<()>;\n\n async fn drop_column(\n &mut self,\n _table_name: &str,\n _column_name: &str,\n _if_exists: bool,\n ) -> Result<()>;\n}\n")))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/1a3daba8.ac1ba8e8.js b/docs/0.16.0/assets/js/1a3daba8.ac1ba8e8.js new file mode 100644 index 00000000..b2fb4fb2 --- /dev/null +++ b/docs/0.16.0/assets/js/1a3daba8.ac1ba8e8.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[4726],{5680:(e,n,t)=>{t.d(n,{xA:()=>c,yg:()=>d});var r=t(6540);function a(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function o(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function l(e){for(var n=1;n=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var p=r.createContext({}),s=function(e){var n=r.useContext(p),t=n;return e&&(t="function"==typeof e?e(n):l(l({},n),e)),t},c=function(e){var n=s(e.components);return r.createElement(p.Provider,{value:n},e.children)},u="mdxType",y={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},g=r.forwardRef((function(e,n){var t=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,c=i(e,["components","mdxType","originalType","parentName"]),u=s(t),g=a,d=u["".concat(p,".").concat(g)]||u[g]||y[g]||o;return t?r.createElement(d,l(l({ref:n},c),{},{components:t})):r.createElement(d,l({ref:n},c))}));function d(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var o=t.length,l=new Array(o);l[0]=g;var i={};for(var p in n)hasOwnProperty.call(n,p)&&(i[p]=n[p]);i.originalType=e,i[u]="string"==typeof e?e:a,l[1]=i;for(var s=2;s{t.r(n),t.d(n,{assets:()=>p,contentTitle:()=>l,default:()=>y,frontMatter:()=>o,metadata:()=>i,toc:()=>s});var r=t(8168),a=(t(6540),t(5680));const o={},l="POINT",i={unversionedId:"sql-syntax/functions/geometry/point",id:"sql-syntax/functions/geometry/point",title:"POINT",description:"The POINT function creates a point value using the provided x and y coordinates. A point value represents a two-dimensional geometric point with a pair of floating-point numbers, often used for storing spatial data.",source:"@site/docs/sql-syntax/functions/geometry/point.md",sourceDirName:"sql-syntax/functions/geometry",slug:"/sql-syntax/functions/geometry/point",permalink:"/docs/0.16.0/sql-syntax/functions/geometry/point",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"GET_Y",permalink:"/docs/0.16.0/sql-syntax/functions/geometry/get-y"},next:{title:"CAST",permalink:"/docs/0.16.0/sql-syntax/functions/others/cast"}},p={},s=[{value:"Syntax",id:"syntax",level:2},{value:"Examples",id:"examples",level:2}],c={toc:s},u="wrapper";function y(e){let{components:n,...t}=e;return(0,a.yg)(u,(0,r.A)({},c,t,{components:n,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"point"},"POINT"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"POINT")," function creates a point value using the provided x and y coordinates. A point value represents a two-dimensional geometric point with a pair of floating-point numbers, often used for storing spatial data."),(0,a.yg)("h2",{id:"syntax"},"Syntax"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"POINT(x, y)\n")),(0,a.yg)("h2",{id:"examples"},"Examples"),(0,a.yg)("p",null,"Create a table with a ",(0,a.yg)("inlineCode",{parentName:"p"},"POINT")," data type column:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE Foo (point_field POINT);\n")),(0,a.yg)("p",null,"Insert a record with a point value:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO Foo VALUES (POINT(0.3134, 0.156));\n")),(0,a.yg)("p",null,"Select the ",(0,a.yg)("inlineCode",{parentName:"p"},"point_field")," column:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT point_field AS point_field FROM Foo;\n")),(0,a.yg)("p",null,"Update the ",(0,a.yg)("inlineCode",{parentName:"p"},"point_field")," column:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"UPDATE Foo SET point_field = POINT(2.0, 1.0) WHERE point_field = POINT(0.3134, 0.156);\n")),(0,a.yg)("p",null,"Select the updated ",(0,a.yg)("inlineCode",{parentName:"p"},"point_field")," column:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT point_field AS point_field FROM Foo;\n")),(0,a.yg)("p",null,"Delete the record with the specified point value:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"DELETE FROM Foo WHERE point_field = POINT(2.0, 1.0);\n")),(0,a.yg)("p",null,"Casting a string to a ",(0,a.yg)("inlineCode",{parentName:"p"},"POINT"),":"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT CAST('POINT(-71.064544 42.28787)' AS POINT) AS pt;\n")))}y.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/1b8ca8c3.4358a704.js b/docs/0.16.0/assets/js/1b8ca8c3.4358a704.js new file mode 100644 index 00000000..b3646389 --- /dev/null +++ b/docs/0.16.0/assets/js/1b8ca8c3.4358a704.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[3772],{5680:(e,n,t)=>{t.d(n,{xA:()=>g,yg:()=>f});var r=t(6540);function a(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function o(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function l(e){for(var n=1;n=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var s=r.createContext({}),u=function(e){var n=r.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):l(l({},n),e)),t},g=function(e){var n=u(e.components);return r.createElement(s.Provider,{value:n},e.children)},p="mdxType",c={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},m=r.forwardRef((function(e,n){var t=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,g=i(e,["components","mdxType","originalType","parentName"]),p=u(t),m=a,f=p["".concat(s,".").concat(m)]||p[m]||c[m]||o;return t?r.createElement(f,l(l({ref:n},g),{},{components:t})):r.createElement(f,l({ref:n},g))}));function f(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var o=t.length,l=new Array(o);l[0]=m;var i={};for(var s in n)hasOwnProperty.call(n,s)&&(i[s]=n[s]);i.originalType=e,i[p]="string"==typeof e?e:a,l[1]=i;for(var u=2;u{t.r(n),t.d(n,{assets:()=>s,contentTitle:()=>l,default:()=>c,frontMatter:()=>o,metadata:()=>i,toc:()=>u});var r=t(8168),a=(t(6540),t(5680));const o={},l="FLOOR",i={unversionedId:"sql-syntax/functions/math/floor",id:"sql-syntax/functions/math/floor",title:"FLOOR",description:"The FLOOR function is used to round a number down to the nearest integer value. It takes a single floating-point or integer value as its argument and returns a floating-point value.",source:"@site/docs/sql-syntax/functions/math/floor.md",sourceDirName:"sql-syntax/functions/math",slug:"/sql-syntax/functions/math/floor",permalink:"/docs/0.16.0/sql-syntax/functions/math/floor",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"EXP",permalink:"/docs/0.16.0/sql-syntax/functions/math/exp"},next:{title:"GCD",permalink:"/docs/0.16.0/sql-syntax/functions/math/gcd"}},s={},u=[{value:"Syntax",id:"syntax",level:2},{value:"Examples",id:"examples",level:2},{value:"Example 1: Using FLOOR function",id:"example-1-using-floor-function",level:3},{value:"Errors",id:"errors",level:2},{value:"Example 2: Using FLOOR with a string argument",id:"example-2-using-floor-with-a-string-argument",level:3},{value:"Example 3: Using FLOOR with a boolean argument",id:"example-3-using-floor-with-a-boolean-argument",level:3}],g={toc:u},p="wrapper";function c(e){let{components:n,...t}=e;return(0,a.yg)(p,(0,r.A)({},g,t,{components:n,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"floor"},"FLOOR"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"FLOOR")," function is used to round a number down to the nearest integer value. It takes a single floating-point or integer value as its argument and returns a floating-point value."),(0,a.yg)("h2",{id:"syntax"},"Syntax"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"FLOOR(value)\n")),(0,a.yg)("h2",{id:"examples"},"Examples"),(0,a.yg)("p",null,"Let's consider a table named ",(0,a.yg)("inlineCode",{parentName:"p"},"SingleItem")," with the following schema:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE SingleItem (id INTEGER);\n")),(0,a.yg)("p",null,"Insert a row into the ",(0,a.yg)("inlineCode",{parentName:"p"},"SingleItem")," table:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO SingleItem VALUES (0);\n")),(0,a.yg)("h3",{id:"example-1-using-floor-function"},"Example 1: Using FLOOR function"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT\nFLOOR(0.3) as floor1,\nFLOOR(-0.8) as floor2,\nFLOOR(10) as floor3,\nFLOOR(6.87421) as floor4\nFROM SingleItem;\n")),(0,a.yg)("p",null,"Result:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre"},"floor1 | floor2 | floor3 | floor4\n-------+--------+--------+--------\n 0.0 | -1.0 | 10.0 | 6.0\n")),(0,a.yg)("p",null,"Note that the returned values are floating-point numbers, even though they represent integer values."),(0,a.yg)("h2",{id:"errors"},"Errors"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"FLOOR")," function expects a floating-point or integer value as its argument. Providing any other type, such as a string or boolean, will result in an error."),(0,a.yg)("h3",{id:"example-2-using-floor-with-a-string-argument"},"Example 2: Using FLOOR with a string argument"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT FLOOR('string') AS floor FROM SingleItem;\n")),(0,a.yg)("p",null,"Error: Function requires a floating-point or integer value."),(0,a.yg)("h3",{id:"example-3-using-floor-with-a-boolean-argument"},"Example 3: Using FLOOR with a boolean argument"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT FLOOR(TRUE) AS floor FROM SingleItem;\n")),(0,a.yg)("p",null,"Error: Function requires a floating-point or integer value."))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/1be78505.08a4249d.js b/docs/0.16.0/assets/js/1be78505.08a4249d.js new file mode 100644 index 00000000..330d1474 --- /dev/null +++ b/docs/0.16.0/assets/js/1be78505.08a4249d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[8714,1774],{10:(e,t,n)=>{n.r(t),n.d(t,{default:()=>ge});var a=n(6540),o=n(53),l=n(1003),r=n(7559),c=n(2967),i=n(1754),s=n(2252),d=n(6588),m=n(9408),u=n(1312),b=n(3104),p=n(5062);const h={backToTopButton:"backToTopButton_sjWU",backToTopButtonShow:"backToTopButtonShow_xfvO"};function E(){const{shown:e,scrollToTop:t}=function(e){let{threshold:t}=e;const[n,o]=(0,a.useState)(!1),l=(0,a.useRef)(!1),{startScroll:r,cancelScroll:c}=(0,b.gk)();return(0,b.Mq)(((e,n)=>{let{scrollY:a}=e;const r=n?.scrollY;r&&(l.current?l.current=!1:a>=r?(c(),o(!1)):a{e.location.hash&&(l.current=!0,o(!1))})),{shown:n,scrollToTop:()=>r(0)}}({threshold:300});return a.createElement("button",{"aria-label":(0,u.T)({id:"theme.BackToTopButton.buttonAriaLabel",message:"Scroll back to top",description:"The ARIA label for the back to top button"}),className:(0,o.A)("clean-btn",r.G.common.backToTopButton,h.backToTopButton,e&&h.backToTopButtonShow),type:"button",onClick:t})}var f=n(3109),g=n(6347),v=n(4581),_=n(6342),A=n(3465),C=n(8168);function k(e){return a.createElement("svg",(0,C.A)({width:"20",height:"20","aria-hidden":"true"},e),a.createElement("g",{fill:"#7a7a7a"},a.createElement("path",{d:"M9.992 10.023c0 .2-.062.399-.172.547l-4.996 7.492a.982.982 0 01-.828.454H1c-.55 0-1-.453-1-1 0-.2.059-.403.168-.551l4.629-6.942L.168 3.078A.939.939 0 010 2.528c0-.548.45-.997 1-.997h2.996c.352 0 .649.18.828.45L9.82 9.472c.11.148.172.347.172.55zm0 0"}),a.createElement("path",{d:"M19.98 10.023c0 .2-.058.399-.168.547l-4.996 7.492a.987.987 0 01-.828.454h-3c-.547 0-.996-.453-.996-1 0-.2.059-.403.168-.551l4.625-6.942-4.625-6.945a.939.939 0 01-.168-.55 1 1 0 01.996-.997h3c.348 0 .649.18.828.45l4.996 7.492c.11.148.168.347.168.55zm0 0"})))}const S={collapseSidebarButton:"collapseSidebarButton_PEFL",collapseSidebarButtonIcon:"collapseSidebarButtonIcon_kv0_"};function N(e){let{onClick:t}=e;return a.createElement("button",{type:"button",title:(0,u.T)({id:"theme.docs.sidebar.collapseButtonTitle",message:"Collapse sidebar",description:"The title attribute for collapse button of doc sidebar"}),"aria-label":(0,u.T)({id:"theme.docs.sidebar.collapseButtonAriaLabel",message:"Collapse sidebar",description:"The title attribute for collapse button of doc sidebar"}),className:(0,o.A)("button button--secondary button--outline",S.collapseSidebarButton),onClick:t},a.createElement(k,{className:S.collapseSidebarButtonIcon}))}var T=n(5041),I=n(9532);const x=Symbol("EmptyContext"),B=a.createContext(x);function w(e){let{children:t}=e;const[n,o]=(0,a.useState)(null),l=(0,a.useMemo)((()=>({expandedItem:n,setExpandedItem:o})),[n]);return a.createElement(B.Provider,{value:l},t)}var y=n(1422),L=n(9169),M=n(5489),H=n(2303);function P(e){let{categoryLabel:t,onClick:n}=e;return a.createElement("button",{"aria-label":(0,u.T)({id:"theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel",message:"Toggle the collapsible sidebar category '{label}'",description:"The ARIA label to toggle the collapsible sidebar category"},{label:t}),type:"button",className:"clean-btn menu__caret",onClick:n})}function G(e){let{item:t,onItemClick:n,activePath:l,level:c,index:s,...d}=e;const{items:m,label:u,collapsible:b,className:p,href:h}=t,{docs:{sidebar:{autoCollapseCategories:E}}}=(0,_.p)(),f=function(e){const t=(0,H.A)();return(0,a.useMemo)((()=>e.href?e.href:!t&&e.collapsible?(0,i._o)(e):void 0),[e,t])}(t),g=(0,i.w8)(t,l),v=(0,L.ys)(h,l),{collapsed:A,setCollapsed:k}=(0,y.u)({initialState:()=>!!b&&(!g&&t.collapsed)}),{expandedItem:S,setExpandedItem:N}=function(){const e=(0,a.useContext)(B);if(e===x)throw new I.dV("DocSidebarItemsExpandedStateProvider");return e}(),T=function(e){void 0===e&&(e=!A),N(e?null:s),k(e)};return function(e){let{isActive:t,collapsed:n,updateCollapsed:o}=e;const l=(0,I.ZC)(t);(0,a.useEffect)((()=>{t&&!l&&n&&o(!1)}),[t,l,n,o])}({isActive:g,collapsed:A,updateCollapsed:T}),(0,a.useEffect)((()=>{b&&null!=S&&S!==s&&E&&k(!0)}),[b,S,s,k,E]),a.createElement("li",{className:(0,o.A)(r.G.docs.docSidebarItemCategory,r.G.docs.docSidebarItemCategoryLevel(c),"menu__list-item",{"menu__list-item--collapsed":A},p)},a.createElement("div",{className:(0,o.A)("menu__list-item-collapsible",{"menu__list-item-collapsible--active":v})},a.createElement(M.A,(0,C.A)({className:(0,o.A)("menu__link",{"menu__link--sublist":b,"menu__link--sublist-caret":!h&&b,"menu__link--active":g}),onClick:b?e=>{n?.(t),h?T(!1):(e.preventDefault(),T())}:()=>{n?.(t)},"aria-current":v?"page":void 0,"aria-expanded":b?!A:void 0,href:b?f??"#":f},d),u),h&&b&&a.createElement(P,{categoryLabel:u,onClick:e=>{e.preventDefault(),T()}})),a.createElement(y.N,{lazy:!0,as:"ul",className:"menu__list",collapsed:A},a.createElement(K,{items:m,tabIndex:A?-1:0,onItemClick:n,activePath:l,level:c+1})))}var F=n(6654),W=n(3186);const D={menuExternalLink:"menuExternalLink_NmtK"};function V(e){let{item:t,onItemClick:n,activePath:l,level:c,index:s,...d}=e;const{href:m,label:u,className:b,autoAddBaseUrl:p}=t,h=(0,i.w8)(t,l),E=(0,F.A)(m);return a.createElement("li",{className:(0,o.A)(r.G.docs.docSidebarItemLink,r.G.docs.docSidebarItemLinkLevel(c),"menu__list-item",b),key:u},a.createElement(M.A,(0,C.A)({className:(0,o.A)("menu__link",!E&&D.menuExternalLink,{"menu__link--active":h}),autoAddBaseUrl:p,"aria-current":h?"page":void 0,to:m},E&&{onClick:n?()=>n(t):void 0},d),u,!E&&a.createElement(W.A,null)))}const U={menuHtmlItem:"menuHtmlItem_M9Kj"};function z(e){let{item:t,level:n,index:l}=e;const{value:c,defaultStyle:i,className:s}=t;return a.createElement("li",{className:(0,o.A)(r.G.docs.docSidebarItemLink,r.G.docs.docSidebarItemLinkLevel(n),i&&[U.menuHtmlItem,"menu__list-item"],s),key:l,dangerouslySetInnerHTML:{__html:c}})}function R(e){let{item:t,...n}=e;switch(t.type){case"category":return a.createElement(G,(0,C.A)({item:t},n));case"html":return a.createElement(z,(0,C.A)({item:t},n));default:return a.createElement(V,(0,C.A)({item:t},n))}}function j(e){let{items:t,...n}=e;return a.createElement(w,null,t.map(((e,t)=>a.createElement(R,(0,C.A)({key:t,item:e,index:t},n)))))}const K=(0,a.memo)(j),q={menu:"menu_SIkG",menuWithAnnouncementBar:"menuWithAnnouncementBar_GW3s"};function O(e){let{path:t,sidebar:n,className:l}=e;const c=function(){const{isActive:e}=(0,T.Mj)(),[t,n]=(0,a.useState)(e);return(0,b.Mq)((t=>{let{scrollY:a}=t;e&&n(0===a)}),[e]),e&&t}();return a.createElement("nav",{"aria-label":(0,u.T)({id:"theme.docs.sidebar.navAriaLabel",message:"Docs sidebar",description:"The ARIA label for the sidebar navigation"}),className:(0,o.A)("menu thin-scrollbar",q.menu,c&&q.menuWithAnnouncementBar,l)},a.createElement("ul",{className:(0,o.A)(r.G.docs.docSidebarMenu,"menu__list")},a.createElement(K,{items:n,activePath:t,level:1})))}const X="sidebar_njMd",Y="sidebarWithHideableNavbar_wUlq",Z="sidebarHidden_VK0M",$="sidebarLogo_isFc";function J(e){let{path:t,sidebar:n,onCollapse:l,isHidden:r}=e;const{navbar:{hideOnScroll:c},docs:{sidebar:{hideable:i}}}=(0,_.p)();return a.createElement("div",{className:(0,o.A)(X,c&&Y,r&&Z)},c&&a.createElement(A.A,{tabIndex:-1,className:$}),a.createElement(O,{path:t,sidebar:n}),i&&a.createElement(N,{onClick:l}))}const Q=a.memo(J);var ee=n(5600),te=n(9876);const ne=e=>{let{sidebar:t,path:n}=e;const l=(0,te.M)();return a.createElement("ul",{className:(0,o.A)(r.G.docs.docSidebarMenu,"menu__list")},a.createElement(K,{items:t,activePath:n,onItemClick:e=>{"category"===e.type&&e.href&&l.toggle(),"link"===e.type&&l.toggle()},level:1}))};function ae(e){return a.createElement(ee.GX,{component:ne,props:e})}const oe=a.memo(ae);function le(e){const t=(0,v.l)(),n="desktop"===t||"ssr"===t,o="mobile"===t;return a.createElement(a.Fragment,null,n&&a.createElement(Q,e),o&&a.createElement(oe,e))}const re={expandButton:"expandButton_m80_",expandButtonIcon:"expandButtonIcon_BlDH"};function ce(e){let{toggleSidebar:t}=e;return a.createElement("div",{className:re.expandButton,title:(0,u.T)({id:"theme.docs.sidebar.expandButtonTitle",message:"Expand sidebar",description:"The ARIA label and title attribute for expand button of doc sidebar"}),"aria-label":(0,u.T)({id:"theme.docs.sidebar.expandButtonAriaLabel",message:"Expand sidebar",description:"The ARIA label and title attribute for expand button of doc sidebar"}),tabIndex:0,role:"button",onKeyDown:t,onClick:t},a.createElement(k,{className:re.expandButtonIcon}))}const ie={docSidebarContainer:"docSidebarContainer_b6E3",docSidebarContainerHidden:"docSidebarContainerHidden_b3ry",sidebarViewport:"sidebarViewport_Xe31"};function se(e){let{children:t}=e;const n=(0,d.t)();return a.createElement(a.Fragment,{key:n?.name??"noSidebar"},t)}function de(e){let{sidebar:t,hiddenSidebarContainer:n,setHiddenSidebarContainer:l}=e;const{pathname:c}=(0,g.zy)(),[i,s]=(0,a.useState)(!1),d=(0,a.useCallback)((()=>{i&&s(!1),!i&&(0,f.O)()&&s(!0),l((e=>!e))}),[l,i]);return a.createElement("aside",{className:(0,o.A)(r.G.docs.docSidebarContainer,ie.docSidebarContainer,n&&ie.docSidebarContainerHidden),onTransitionEnd:e=>{e.currentTarget.classList.contains(ie.docSidebarContainer)&&n&&s(!0)}},a.createElement(se,null,a.createElement("div",{className:(0,o.A)(ie.sidebarViewport,i&&ie.sidebarViewportHidden)},a.createElement(le,{sidebar:t,path:c,onCollapse:d,isHidden:i}),i&&a.createElement(ce,{toggleSidebar:d}))))}const me={docMainContainer:"docMainContainer_gTbr",docMainContainerEnhanced:"docMainContainerEnhanced_Uz_u",docItemWrapperEnhanced:"docItemWrapperEnhanced_czyv"};function ue(e){let{hiddenSidebarContainer:t,children:n}=e;const l=(0,d.t)();return a.createElement("main",{className:(0,o.A)(me.docMainContainer,(t||!l)&&me.docMainContainerEnhanced)},a.createElement("div",{className:(0,o.A)("container padding-top--md padding-bottom--lg",me.docItemWrapper,t&&me.docItemWrapperEnhanced)},n))}const be={docPage:"docPage__5DB",docsWrapper:"docsWrapper_BCFX","themedComponent--light":"themedComponent--light_NU7w"};function pe(e){let{children:t}=e;const n=(0,d.t)(),[o,l]=(0,a.useState)(!1);return a.createElement(m.A,{wrapperClassName:be.docsWrapper},a.createElement(E,null),a.createElement("div",{className:be.docPage},n&&a.createElement(de,{sidebar:n.items,hiddenSidebarContainer:o,setHiddenSidebarContainer:l}),a.createElement(ue,{hiddenSidebarContainer:o},t)))}var he=n(1774),Ee=n(1463);function fe(e){const{versionMetadata:t}=e;return a.createElement(a.Fragment,null,a.createElement(Ee.A,{version:t.version,tag:(0,c.tU)(t.pluginId,t.version)}),a.createElement(l.be,null,t.noIndex&&a.createElement("meta",{name:"robots",content:"noindex, nofollow"})))}function ge(e){const{versionMetadata:t}=e,n=(0,i.mz)(e);if(!n)return a.createElement(he.default,null);const{docElement:c,sidebarName:m,sidebarItems:u}=n;return a.createElement(a.Fragment,null,a.createElement(fe,e),a.createElement(l.e3,{className:(0,o.A)(r.G.wrapper.docsPages,r.G.page.docsDocPage,e.versionMetadata.className)},a.createElement(s.n,{version:t},a.createElement(d.V,{name:m,items:u},a.createElement(pe,null,c)))))}},1774:(e,t,n)=>{n.r(t),n.d(t,{default:()=>c});var a=n(6540),o=n(1312),l=n(1003),r=n(9408);function c(){return a.createElement(a.Fragment,null,a.createElement(l.be,{title:(0,o.T)({id:"theme.NotFound.title",message:"Page Not Found"})}),a.createElement(r.A,null,a.createElement("main",{className:"container margin-vert--xl"},a.createElement("div",{className:"row"},a.createElement("div",{className:"col col--6 col--offset-3"},a.createElement("h1",{className:"hero__title"},a.createElement(o.A,{id:"theme.NotFound.title",description:"The title of the 404 page"},"Page Not Found")),a.createElement("p",null,a.createElement(o.A,{id:"theme.NotFound.p1",description:"The first paragraph of the 404 page"},"We could not find what you were looking for.")),a.createElement("p",null,a.createElement(o.A,{id:"theme.NotFound.p2",description:"The 2nd paragraph of the 404 page"},"Please contact the owner of the site that linked you to the original URL and let them know their link is broken.")))))))}},2252:(e,t,n)=>{n.d(t,{n:()=>r,r:()=>c});var a=n(6540),o=n(9532);const l=a.createContext(null);function r(e){let{children:t,version:n}=e;return a.createElement(l.Provider,{value:n},t)}function c(){const e=(0,a.useContext)(l);if(null===e)throw new o.dV("DocsVersionProvider");return e}}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/1c41eae2.66378d8d.js b/docs/0.16.0/assets/js/1c41eae2.66378d8d.js new file mode 100644 index 00000000..c096d0cb --- /dev/null +++ b/docs/0.16.0/assets/js/1c41eae2.66378d8d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[1717],{2945:s=>{s.exports=JSON.parse('{"name":"docusaurus-plugin-content-blog","id":"default"}')}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/1c93e70c.77ab6302.js b/docs/0.16.0/assets/js/1c93e70c.77ab6302.js new file mode 100644 index 00000000..692bb2e1 --- /dev/null +++ b/docs/0.16.0/assets/js/1c93e70c.77ab6302.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[6276],{5680:(e,t,n)=>{n.d(t,{xA:()=>p,yg:()=>c});var a=n(6540);function l(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t=0||(l[n]=e[n]);return l}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(l[n]=e[n])}return l}var u=a.createContext({}),s=function(e){var t=a.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=s(e.components);return a.createElement(u.Provider,{value:t},e.children)},g="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,l=e.mdxType,r=e.originalType,u=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),g=s(n),m=l,c=g["".concat(u,".").concat(m)]||g[m]||d[m]||r;return n?a.createElement(c,o(o({ref:t},p),{},{components:n})):a.createElement(c,o({ref:t},p))}));function c(e,t){var n=arguments,l=t&&t.mdxType;if("string"==typeof e||l){var r=n.length,o=new Array(r);o[0]=m;var i={};for(var u in t)hasOwnProperty.call(t,u)&&(i[u]=t[u]);i.originalType=e,i[g]="string"==typeof e?e:l,o[1]=i;for(var s=2;s{n.r(t),n.d(t,{assets:()=>u,contentTitle:()=>o,default:()=>d,frontMatter:()=>r,metadata:()=>i,toc:()=>s});var a=n(8168),l=(n(6540),n(5680));const r={sidebar_position:4},o="Command-Line Interface",i={unversionedId:"getting-started/cli",id:"getting-started/cli",title:"Command-Line Interface",description:"Introduction",source:"@site/docs/getting-started/cli.md",sourceDirName:"getting-started",slug:"/getting-started/cli",permalink:"/docs/0.16.0/getting-started/cli",draft:!1,tags:[],version:"current",sidebarPosition:4,frontMatter:{sidebar_position:4},sidebar:"autoSidebar",previous:{title:"Node.js",permalink:"/docs/0.16.0/getting-started/nodejs"},next:{title:"Introduction",permalink:"/docs/0.16.0/sql-syntax/intro"}},u={},s=[{value:"Introduction",id:"introduction",level:2},{value:"Installation",id:"installation",level:2},{value:"Running the CLI",id:"running-the-cli",level:2},{value:"--execute",id:"--execute",level:3},{value:"--path",id:"--path",level:3},{value:"--storage",id:"--storage",level:3},{value:"Dot command",id:"dot-command",level:2},{value:".show",id:"show",level:3},{value:".set",id:"set",level:3},{value:"Print options",id:"print-options",level:4},{value:".edit",id:"edit",level:3},{value:"With last executed SQL",id:"with-last-executed-sql",level:4},{value:"With PATH",id:"with-path",level:4},{value:".execute",id:"execute",level:3},{value:".run",id:"run",level:3},{value:"More commands",id:"more-commands",level:3},{value:"Migration using CLI",id:"migration-using-cli",level:2}],p={toc:s},g="wrapper";function d(e){let{components:t,...n}=e;return(0,l.yg)(g,(0,a.A)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,l.yg)("h1",{id:"command-line-interface"},"Command-Line Interface"),(0,l.yg)("h2",{id:"introduction"},"Introduction"),(0,l.yg)("p",null,"The Command-Line Interface (CLI) is a tool that allows interactive execution of SQL on GlueSQL. It supports Dot commands for more convenient use, and the .edit command allows immediate modification of query files, which can then be executed with .execute. In addition, it supports HTML table format output for SQL results, making it possible to use the results directly on the web."),(0,l.yg)("h2",{id:"installation"},"Installation"),(0,l.yg)("p",null,"To install the GlueSQL Command-Line Interface (CLI), run the following command:"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre"},"$ cargo install gluesql\n")),(0,l.yg)("h2",{id:"running-the-cli"},"Running the CLI"),(0,l.yg)("p",null,"Once you have installed the GlueSQL CLI, you can use it to interact with your database. The CLI has several options that you can use to customize your database configuration:"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre"},"$ gluesql [--execute ~/sql_path] [--path ~/data_path --storage={sled | json}]\n")),(0,l.yg)("h3",{id:"--execute"},"--execute"),(0,l.yg)("p",null,"This option allows you to execute a SQL query that is stored in a specific file path. You need to provide the path to the SQL file that contains the query you want to execute. For example, you can use the following command to execute a file located at ",(0,l.yg)("inlineCode",{parentName:"p"},"~/sql_path/query.sql")),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre"},"gluesql --execute ~/sql_path/query.sql\n")),(0,l.yg)("h3",{id:"--path"},"--path"),(0,l.yg)("p",null,"This option allows you to specify the path to your database's data directory. By default, GlueSQL stores your database in the current directory. However, you can use the --path option to specify a custom directory where you want to store your database files. For example, you can use the following command to specify a custom data directory ",(0,l.yg)("inlineCode",{parentName:"p"},"~/mydatabase"),":"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre"},"gluesql --path ~/mydatabase\n")),(0,l.yg)("h3",{id:"--storage"},"--storage"),(0,l.yg)("p",null,"This option allows you to specify the storage engine you want to use for your database. By default, GlueSQL uses the ",(0,l.yg)("a",{parentName:"p",href:"../storages/supported-storages/memory-storage"},(0,l.yg)("inlineCode",{parentName:"a"},"memory"))," storage engine. However, you can also use ",(0,l.yg)("a",{parentName:"p",href:"../storages/supported-storages/sled-storage"},(0,l.yg)("inlineCode",{parentName:"a"},"sled"))," or ",(0,l.yg)("a",{parentName:"p",href:"../storages/supported-storages/json-storage"},(0,l.yg)("inlineCode",{parentName:"a"},"json"))," storage engine by using the --storage option. Note that ",(0,l.yg)("inlineCode",{parentName:"p"},"sled")," and ",(0,l.yg)("inlineCode",{parentName:"p"},"json")," should be with ",(0,l.yg)("inlineCode",{parentName:"p"},"--path")," option. For example, you can use the following command to specify the ",(0,l.yg)("inlineCode",{parentName:"p"},"json")," storage engine:"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre"},"gluesql --path ~/mydatabase --storage=json\n")),(0,l.yg)("h2",{id:"dot-command"},"Dot command"),(0,l.yg)("h3",{id:"show"},".show"),(0,l.yg)("p",null,"This command shows current ",(0,l.yg)("a",{parentName:"p",href:"#print-options"},"Print options"),"."),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre"},'gluesql> .show all\ntabular ON\ncolsep "|"\ncolwrap ""\nheading ON\n')),(0,l.yg)("p",null,"or you can specify a option"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre"},'gluesql> .show colsep\ncolsep "|"\n')),(0,l.yg)("h3",{id:"set"},".set"),(0,l.yg)("p",null,"This command can set each Print options"),(0,l.yg)("h4",{id:"print-options"},"Print options"),(0,l.yg)("table",null,(0,l.yg)("thead",{parentName:"table"},(0,l.yg)("tr",{parentName:"thead"},(0,l.yg)("th",{parentName:"tr",align:null},"command"),(0,l.yg)("th",{parentName:"tr",align:null},"description"))),(0,l.yg)("tbody",{parentName:"table"},(0,l.yg)("tr",{parentName:"tbody"},(0,l.yg)("td",{parentName:"tr",align:null},"tabular {ON","|","OFF}"),(0,l.yg)("td",{parentName:"tr",align:null},"turn on/off html table format")),(0,l.yg)("tr",{parentName:"tbody"},(0,l.yg)("td",{parentName:"tr",align:null},"colsep {SEPARATOR}"),(0,l.yg)("td",{parentName:"tr",align:null},"set column separator(",(0,l.yg)("inlineCode",{parentName:"td"},"tabular OFF")," only)")),(0,l.yg)("tr",{parentName:"tbody"},(0,l.yg)("td",{parentName:"tr",align:null},"colwrap {WRAPPER}"),(0,l.yg)("td",{parentName:"tr",align:null},"set column wrapper(",(0,l.yg)("inlineCode",{parentName:"td"},"tabular OFF")," only)")),(0,l.yg)("tr",{parentName:"tbody"},(0,l.yg)("td",{parentName:"tr",align:null},"heading {ON","|","OFF}"),(0,l.yg)("td",{parentName:"tr",align:null},"turn on/off heading")))),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre"},"gluesql> VALUES (1, 'Glue'), (2, 'SQL');\n| column1 | column2 |\n|---------|---------|\n| 1 | Glue |\n| 2 | SQL |\n\ngluesql> .set tabular off\ngluesql> VALUES (1, 'Glue'), (2, 'SQL');\ncolumn1|column2\n1|Glue\n2|SQL\ngluesql> .set colsep ,\ngluesql> VALUES (1, 'Glue'), (2, 'SQL');\ncolumn1,column2\n1,Glue\n2,SQL\ngluesql> .set colwrap '\ngluesql> VALUES (1, 'Glue'), (2, 'SQL');\n'column1','column2'\n'1','Glue'\n'2','SQL'\ngluesql> .set heading off\ngluesql> VALUES (1, 'Glue'), (2, 'SQL');\n'1','Glue'\n'2','SQL'\n")),(0,l.yg)("h3",{id:"edit"},".edit"),(0,l.yg)("p",null,"This command open editor with last executed SQL or PATH"),(0,l.yg)("h4",{id:"with-last-executed-sql"},"With last executed SQL"),(0,l.yg)("p",null,"if you execute ",(0,l.yg)("inlineCode",{parentName:"p"},".edit"),", it opens specified (set on ",(0,l.yg)("inlineCode",{parentName:"p"},"$EDITOR")," env) or OS default editor."),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"$ export $EDITOR=vi\n$ gluesql\ngluesql> VALUES (1, 'Glue'), (2, 'SQL');\n| column1 | column2 |\n|---------|---------|\n| 1 | Glue |\n| 2 | SQL |\ngluesql> .edit\n")),(0,l.yg)("p",null,"Last executed SQL is opened with ",(0,l.yg)("inlineCode",{parentName:"p"},"vi")),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"--! /tmp/Glue_xxxxx.sql\nVALUES (1, 'Glue'), (2, 'SQL');\n")),(0,l.yg)("h4",{id:"with-path"},"With PATH"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"gluesql> .edit insert.sql\n")),(0,l.yg)("p",null,"It opens editor and shows the contents of ",(0,l.yg)("inlineCode",{parentName:"p"},"create_insert.sql")),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"--! create_insert.sql\nCREATE TABLE Items (id INT, name TEXT);\nINSERT INTO Items VALUES (1, 'Glue'), (2, 'SQL');\n")),(0,l.yg)("h3",{id:"execute"},".execute"),(0,l.yg)("p",null,"This command executes SQL from PATH"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"gluesql> .execute create_insert.sql\nTable created\n\n2 rows inserted\n")),(0,l.yg)("h3",{id:"run"},".run"),(0,l.yg)("p",null,"This command executes last executed command again."),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"gluesql> VALUES (1, 'Glue'), (2, 'SQL');\n| column1 | column2 |\n|---------|---------|\n| 1 | Glue |\n| 2 | SQL |\n\ngluesql> .run\n| column1 | column2 |\n|---------|---------|\n| 1 | Glue |\n| 2 | SQL |\n")),(0,l.yg)("p",null,"Also possible to combinate with ",(0,l.yg)("inlineCode",{parentName:"p"},".edit")),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"gluesql> VALUES (1, 'Glue'), (2, 'SQL');\n| column1 | column2 |\n|---------|---------|\n| 1 | Glue |\n| 2 | SQL |\n\ngluesql> .edit\n")),(0,l.yg)("p",null,"edit to add ",(0,l.yg)("inlineCode",{parentName:"p"},"(3, 'Rust')")),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"--! /tmp/Glue_xxxxxx.sql\nVALUES (1, 'Glue'), (2, 'SQL'), (3, 'Rust')\n")),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"gluesql> .run\n| column1 | column2 |\n|---------|---------|\n| 1 | Glue |\n| 2 | SQL |\n| 3 | Rust |\n")),(0,l.yg)("h3",{id:"more-commands"},"More commands"),(0,l.yg)("p",null,"If you execute ",(0,l.yg)("inlineCode",{parentName:"p"},".help"),", you can see various helper command starting with dot(",(0,l.yg)("inlineCode",{parentName:"p"},"."),")"),(0,l.yg)("table",null,(0,l.yg)("thead",{parentName:"table"},(0,l.yg)("tr",{parentName:"thead"},(0,l.yg)("th",{parentName:"tr",align:null},"command"),(0,l.yg)("th",{parentName:"tr",align:null},"description"))),(0,l.yg)("tbody",{parentName:"table"},(0,l.yg)("tr",{parentName:"tbody"},(0,l.yg)("td",{parentName:"tr",align:null},".help"),(0,l.yg)("td",{parentName:"tr",align:null},"show help")),(0,l.yg)("tr",{parentName:"tbody"},(0,l.yg)("td",{parentName:"tr",align:null},".quit"),(0,l.yg)("td",{parentName:"tr",align:null},"quit program")),(0,l.yg)("tr",{parentName:"tbody"},(0,l.yg)("td",{parentName:"tr",align:null},".tables"),(0,l.yg)("td",{parentName:"tr",align:null},"show table names")),(0,l.yg)("tr",{parentName:"tbody"},(0,l.yg)("td",{parentName:"tr",align:null},".functions"),(0,l.yg)("td",{parentName:"tr",align:null},"show function names")),(0,l.yg)("tr",{parentName:"tbody"},(0,l.yg)("td",{parentName:"tr",align:null},".columns TABLE"),(0,l.yg)("td",{parentName:"tr",align:null},"show columns from TABLE")),(0,l.yg)("tr",{parentName:"tbody"},(0,l.yg)("td",{parentName:"tr",align:null},".version"),(0,l.yg)("td",{parentName:"tr",align:null},"show version")),(0,l.yg)("tr",{parentName:"tbody"},(0,l.yg)("td",{parentName:"tr",align:null},".execute PATH"),(0,l.yg)("td",{parentName:"tr",align:null},"execute SQL from PATH")),(0,l.yg)("tr",{parentName:"tbody"},(0,l.yg)("td",{parentName:"tr",align:null},".spool PATH","|","off"),(0,l.yg)("td",{parentName:"tr",align:null},"spool to PATH or off")),(0,l.yg)("tr",{parentName:"tbody"},(0,l.yg)("td",{parentName:"tr",align:null},".show OPTION"),(0,l.yg)("td",{parentName:"tr",align:null},"show print option eg).show all")),(0,l.yg)("tr",{parentName:"tbody"},(0,l.yg)("td",{parentName:"tr",align:null},".set OPTION"),(0,l.yg)("td",{parentName:"tr",align:null},"set print option eg).set tabular off")),(0,l.yg)("tr",{parentName:"tbody"},(0,l.yg)("td",{parentName:"tr",align:null},".edit ","[PATH]"),(0,l.yg)("td",{parentName:"tr",align:null},"open editor with last command or PATH")),(0,l.yg)("tr",{parentName:"tbody"},(0,l.yg)("td",{parentName:"tr",align:null},".run"),(0,l.yg)("td",{parentName:"tr",align:null},"execute last command")))),(0,l.yg)("h2",{id:"migration-using-cli"},"Migration using CLI"),(0,l.yg)("p",null,"GlueSQL CLI supports generating SQL scripts for dumping whole schemas and data."),(0,l.yg)("p",null,"For instance, if you want to dump your database schema and data to a file named ",(0,l.yg)("inlineCode",{parentName:"p"},"dump.sql"),", you can use the following command:"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre"},"$ gluesql --path ~/glue_data --dump ./dump.sql\n")),(0,l.yg)("p",null,"This will create a SQL script in the current directory that you can use to recreate your database."),(0,l.yg)("p",null,"If you want to import the database from the ",(0,l.yg)("inlineCode",{parentName:"p"},"dump.sql")," file, you can use the following command:"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre"},"$ gluesql --execute ./dump.sql --path ~/new_data --storage=sled\n")),(0,l.yg)("p",null,"This will create a new database in the specified path, using the Sled Storage engine."),(0,l.yg)("p",null,"That's it! You now know how to use GlueSQL to migrate your database schema and data using the CLI."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/1cdac986.f465f273.js b/docs/0.16.0/assets/js/1cdac986.f465f273.js new file mode 100644 index 00000000..36d4f259 --- /dev/null +++ b/docs/0.16.0/assets/js/1cdac986.f465f273.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[7248],{5680:(e,t,n)=>{n.d(t,{xA:()=>l,yg:()=>m});var r=n(6540);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function a(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=r.createContext({}),u=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},l=function(e){var t=u(e.components);return r.createElement(s.Provider,{value:t},e.children)},p="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,s=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),p=u(n),d=o,m=p["".concat(s,".").concat(d)]||p[d]||f[d]||i;return n?r.createElement(m,a(a({ref:t},l),{},{components:n})):r.createElement(m,a({ref:t},l))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,a=new Array(i);a[0]=d;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c[p]="string"==typeof e?e:o,a[1]=c;for(var u=2;u{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>a,default:()=>f,frontMatter:()=>i,metadata:()=>c,toc:()=>u});var r=n(8168),o=(n(6540),n(5680));const i={},a="Text Manipulation",c={unversionedId:"ast-builder/functions/text/text-manipulation",id:"ast-builder/functions/text/text-manipulation",title:"Text Manipulation",description:"Todo",source:"@site/docs/ast-builder/functions/text/text-manipulation.md",sourceDirName:"ast-builder/functions/text",slug:"/ast-builder/functions/text/text-manipulation",permalink:"/docs/0.16.0/ast-builder/functions/text/text-manipulation",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"Position and Indexing",permalink:"/docs/0.16.0/ast-builder/functions/text/position-and-indexing"},next:{title:"Trimming",permalink:"/docs/0.16.0/ast-builder/functions/text/trimming"}},s={},u=[{value:"Todo",id:"todo",level:2}],l={toc:u},p="wrapper";function f(e){let{components:t,...n}=e;return(0,o.yg)(p,(0,r.A)({},l,n,{components:t,mdxType:"MDXLayout"}),(0,o.yg)("h1",{id:"text-manipulation"},"Text Manipulation"),(0,o.yg)("h2",{id:"todo"},"Todo"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre"},"- CONCAT: Concatenates two or more strings into one.\n- CONCAT_WS: Concatenates two or more strings into one with a separator.\n- SUBSTR: Returns a part of a string.\n- REPEAT: Repeats a string a specified number of times.\n- REVERSE: Reverses the order of the characters in a string.\n")))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/1ce64703.168baa89.js b/docs/0.16.0/assets/js/1ce64703.168baa89.js new file mode 100644 index 00000000..3255c4f2 --- /dev/null +++ b/docs/0.16.0/assets/js/1ce64703.168baa89.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[390],{5680:(e,n,t)=>{t.d(n,{xA:()=>p,yg:()=>g});var r=t(6540);function o(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function a(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function i(e){for(var n=1;n=0||(o[t]=e[t]);return o}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var u=r.createContext({}),c=function(e){var n=r.useContext(u),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},p=function(e){var n=c(e.components);return r.createElement(u.Provider,{value:n},e.children)},d="mdxType",s={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},m=r.forwardRef((function(e,n){var t=e.components,o=e.mdxType,a=e.originalType,u=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),d=c(t),m=o,g=d["".concat(u,".").concat(m)]||d[m]||s[m]||a;return t?r.createElement(g,i(i({ref:n},p),{},{components:t})):r.createElement(g,i({ref:n},p))}));function g(e,n){var t=arguments,o=n&&n.mdxType;if("string"==typeof e||o){var a=t.length,i=new Array(a);i[0]=m;var l={};for(var u in n)hasOwnProperty.call(n,u)&&(l[u]=n[u]);l.originalType=e,l[d]="string"==typeof e?e:o,i[1]=l;for(var c=2;c{t.r(n),t.d(n,{assets:()=>u,contentTitle:()=>i,default:()=>s,frontMatter:()=>a,metadata:()=>l,toc:()=>c});var r=t(8168),o=(t(6540),t(5680));const a={},i="Rounding",l={unversionedId:"ast-builder/functions/math/rounding",id:"ast-builder/functions/math/rounding",title:"Rounding",description:"The AST (Abstract Syntax Tree) Builder in GlueSQL provides several mathematical functions, including round, ceil, and floor. These functions are used to perform rounding operations on floating-point numbers.",source:"@site/docs/ast-builder/functions/math/rounding.md",sourceDirName:"ast-builder/functions/math",slug:"/ast-builder/functions/math/rounding",permalink:"/docs/0.16.0/ast-builder/functions/math/rounding",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"Logarithmic and Exponential",permalink:"/docs/0.16.0/ast-builder/functions/math/logarithmic-and-exponential"},next:{title:"Special Mathematical",permalink:"/docs/0.16.0/ast-builder/functions/math/special-mathematical"}},u={},c=[{value:"Ceil Function",id:"ceil-function",level:2},{value:"Floor Function",id:"floor-function",level:2},{value:"Round Function",id:"round-function",level:2}],p={toc:c},d="wrapper";function s(e){let{components:n,...t}=e;return(0,o.yg)(d,(0,r.A)({},p,t,{components:n,mdxType:"MDXLayout"}),(0,o.yg)("h1",{id:"rounding"},"Rounding"),(0,o.yg)("p",null,"The AST (Abstract Syntax Tree) Builder in GlueSQL provides several mathematical functions, including ",(0,o.yg)("inlineCode",{parentName:"p"},"round"),", ",(0,o.yg)("inlineCode",{parentName:"p"},"ceil"),", and ",(0,o.yg)("inlineCode",{parentName:"p"},"floor"),". These functions are used to perform rounding operations on floating-point numbers."),(0,o.yg)("p",null,"For the sake of this tutorial, we'll assume there's a table named ",(0,o.yg)("inlineCode",{parentName:"p"},"Number")," with columns ",(0,o.yg)("inlineCode",{parentName:"p"},"id")," (of type ",(0,o.yg)("inlineCode",{parentName:"p"},"INTEGER"),") and ",(0,o.yg)("inlineCode",{parentName:"p"},"number")," (of type ",(0,o.yg)("inlineCode",{parentName:"p"},"FLOAT"),")."),(0,o.yg)("h2",{id:"ceil-function"},"Ceil Function"),(0,o.yg)("p",null,"The ",(0,o.yg)("inlineCode",{parentName:"p"},"ceil")," function rounds up the ",(0,o.yg)("inlineCode",{parentName:"p"},"number")," to the nearest integer value that is greater than or equal to ",(0,o.yg)("inlineCode",{parentName:"p"},"number"),"."),(0,o.yg)("p",null,"In GlueSQL, you can call this function in two ways. Both methods are shown below:"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Number")\n .select()\n .project("id")\n .project(ceil("number")) // Method 1: Using the ceil function directly\n .project(col("number").ceil()) // Method 2: Calling the ceil method on a column\n .execute(glue)\n .await;\n')),(0,o.yg)("h2",{id:"floor-function"},"Floor Function"),(0,o.yg)("p",null,"The ",(0,o.yg)("inlineCode",{parentName:"p"},"floor")," function rounds down the ",(0,o.yg)("inlineCode",{parentName:"p"},"number")," to the nearest integer value that is less than or equal to ",(0,o.yg)("inlineCode",{parentName:"p"},"number"),"."),(0,o.yg)("p",null,"Again, there are two ways to call this function in GlueSQL:"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Number")\n .select()\n .project("id")\n .project(floor("number")) // Method 1: Using the floor function directly\n .project(col("number").floor()) // Method 2: Calling the floor method on a column\n .execute(glue)\n .await;\n')),(0,o.yg)("h2",{id:"round-function"},"Round Function"),(0,o.yg)("p",null,"The ",(0,o.yg)("inlineCode",{parentName:"p"},"round")," function rounds the ",(0,o.yg)("inlineCode",{parentName:"p"},"number")," to the nearest integer. If ",(0,o.yg)("inlineCode",{parentName:"p"},"number")," is halfway between two integers, it rounds towards the nearest even number."),(0,o.yg)("p",null,"The ",(0,o.yg)("inlineCode",{parentName:"p"},"round")," function can also be called in two ways, as demonstrated below:"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Number")\n .select()\n .project("id")\n .project(round("number")) // Method 1: Using the round function directly\n .project(col("number").round()) // Method 2: Calling the round method on a column\n .execute(glue)\n .await;\n')))}s.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/1e4e1fb6.352993fe.js b/docs/0.16.0/assets/js/1e4e1fb6.352993fe.js new file mode 100644 index 00000000..4fe92682 --- /dev/null +++ b/docs/0.16.0/assets/js/1e4e1fb6.352993fe.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[7889],{1966:s=>{s.exports=JSON.parse('{"name":"docusaurus-plugin-content-docs","id":"default"}')}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/20e2ece2.6327fef8.js b/docs/0.16.0/assets/js/20e2ece2.6327fef8.js new file mode 100644 index 00000000..8dbb2bf2 --- /dev/null +++ b/docs/0.16.0/assets/js/20e2ece2.6327fef8.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[9957],{5680:(e,t,a)=>{a.d(t,{xA:()=>d,yg:()=>g});var n=a(6540);function i(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function o(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function s(e){for(var t=1;t=0||(i[a]=e[a]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(i[a]=e[a])}return i}var l=n.createContext({}),u=function(e){var t=n.useContext(l),a=t;return e&&(a="function"==typeof e?e(t):s(s({},t),e)),a},d=function(e){var t=u(e.components);return n.createElement(l.Provider,{value:t},e.children)},c="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},p=n.forwardRef((function(e,t){var a=e.components,i=e.mdxType,o=e.originalType,l=e.parentName,d=r(e,["components","mdxType","originalType","parentName"]),c=u(a),p=i,g=c["".concat(l,".").concat(p)]||c[p]||h[p]||o;return a?n.createElement(g,s(s({ref:t},d),{},{components:a})):n.createElement(g,s({ref:t},d))}));function g(e,t){var a=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=a.length,s=new Array(o);s[0]=p;var r={};for(var l in t)hasOwnProperty.call(t,l)&&(r[l]=t[l]);r.originalType=e,r[c]="string"==typeof e?e:i,s[1]=r;for(var u=2;u{a.r(t),a.d(t,{assets:()=>l,contentTitle:()=>s,default:()=>h,frontMatter:()=>o,metadata:()=>r,toc:()=>u});var n=a(8168),i=(a(6540),a(5680));const o={title:"GlueSQL - Revolutionizing Databases by Unifying Query Interfaces",description:"GlueSQL - Revolutionizing Databases by Unifying Query Interfaces",slug:"revolutionizing-databases-by-unifying-query-interfaces",authors:[{name:"Taehoon Moon",title:"Creator of GlueSQL",url:"https://github.com/panarch",image_url:"https://github.com/panarch.png"}],tags:["gluesql","query-interface","database","proposal"]},s="GlueSQL: Revolutionizing Databases by Unifying Query Interfaces",r={permalink:"/docs/0.16.0/blog/revolutionizing-databases-by-unifying-query-interfaces",source:"@site/blog/2023-05-30-revolutionizing-databases-by-unifying-query-interfaces.md",title:"GlueSQL - Revolutionizing Databases by Unifying Query Interfaces",description:"GlueSQL - Revolutionizing Databases by Unifying Query Interfaces",date:"2023-05-30T00:00:00.000Z",formattedDate:"May 30, 2023",tags:[{label:"gluesql",permalink:"/docs/0.16.0/blog/tags/gluesql"},{label:"query-interface",permalink:"/docs/0.16.0/blog/tags/query-interface"},{label:"database",permalink:"/docs/0.16.0/blog/tags/database"},{label:"proposal",permalink:"/docs/0.16.0/blog/tags/proposal"}],readingTime:13.07,hasTruncateMarker:!1,authors:[{name:"Taehoon Moon",title:"Creator of GlueSQL",url:"https://github.com/panarch",image_url:"https://github.com/panarch.png",imageURL:"https://github.com/panarch.png"}],frontMatter:{title:"GlueSQL - Revolutionizing Databases by Unifying Query Interfaces",description:"GlueSQL - Revolutionizing Databases by Unifying Query Interfaces",slug:"revolutionizing-databases-by-unifying-query-interfaces",authors:[{name:"Taehoon Moon",title:"Creator of GlueSQL",url:"https://github.com/panarch",image_url:"https://github.com/panarch.png",imageURL:"https://github.com/panarch.png"}],tags:["gluesql","query-interface","database","proposal"]},prevItem:{title:"Release v0.15",permalink:"/docs/0.16.0/blog/release-v0.15"},nextItem:{title:"Test-Driven Documentation - Automating User Manual Creation in GlueSQL",permalink:"/docs/0.16.0/blog/test-driven-documentation"}},l={authorsImageUrls:[void 0]},u=[{value:"Introduction",id:"introduction",level:2},{value:"The Problem: Why Reinvent the Database?",id:"the-problem-why-reinvent-the-database",level:2},{value:"The Vision of GlueSQL",id:"the-vision-of-gluesql",level:2},{value:"Benefits to Database Users: Unifying Query Interfaces, Streamlining Software Development, and Reducing Costs",id:"benefits-to-database-users-unifying-query-interfaces-streamlining-software-development-and-reducing-costs",level:2},{value:"Benefits to Database Developers: Drastically Lowering Development Costs and Simplifying the Creation of Purpose-Built Databases",id:"benefits-to-database-developers-drastically-lowering-development-costs-and-simplifying-the-creation-of-purpose-built-databases",level:2},{value:"The Future with GlueSQL",id:"the-future-with-gluesql",level:2},{value:"The Journey of the GlueSQL Team",id:"the-journey-of-the-gluesql-team",level:2},{value:"The Sustainability and Business Aspect of GlueSQL",id:"the-sustainability-and-business-aspect-of-gluesql",level:2},{value:"Conclusion",id:"conclusion",level:2}],d={toc:u},c="wrapper";function h(e){let{components:t,...a}=e;return(0,i.yg)(c,(0,n.A)({},d,a,{components:t,mdxType:"MDXLayout"}),(0,i.yg)("h2",{id:"introduction"},"Introduction"),(0,i.yg)("p",null,"GlueSQL is a versatile database project designed for exceptional portability across a broad range of environments, from embedded systems and servers to web and mobile platforms. The core goal is to support diverse storage environments and manage various data types with a standard SQL approach."),(0,i.yg)("p",null,"Imagine handling files like CSV, JSONL, and Parquet, or transforming key-value or NoSQL databases such as RocksDB, Redis, and MongoDB into SQL-supporting databases\u2014all feasible with GlueSQL. It can also operate with storages supported in web browsers."),(0,i.yg)("p",null,"GlueSQL's essential feature is providing a management layer for these diverse storage scenarios without requiring data migration. The broader aim is to facilitate portability of GlueSQL to any environment supporting read or read-write operations. This extends to APIs like GitHub, or messengers like Discord or Slack."),(0,i.yg)("p",null,"GlueSQL supports both structured and unstructured data and is written in Rust for compatibility with various environments. While portability is its core value, the emphasis is on creating an intuitive, comfortable development environment for easy custom storage implementation."),(0,i.yg)("p",null,"Ultimately, GlueSQL aims to significantly reduce the cost, time, and complexity of developing new databases. By leveraging GlueSQL for the parser, planner, and execution layer, developers can focus on creating specific storage implementations, leading to a more convenient query interface like SQL for many environments."),(0,i.yg)("h2",{id:"the-problem-why-reinvent-the-database"},"The Problem: Why Reinvent the Database?"),(0,i.yg)("p",null,"Despite the numerous database implementations that currently exist, the emergence of new databases continues. The primary reason behind this trend is our need for databases for a broad spectrum of distinct purposes. For instance, new databases are surfacing that are specifically optimized for Large Language Models (LLMs) like ChatGPT. The range is wide and diverse, encompassing embedded databases, OLAP for data analysis, OLTP databases optimized for online transactions, databases specialized for time-series data processing, and many more."),(0,i.yg)("p",null,"With such varied requirements, we find ourselves in constant need of fresh databases. However, constructing a database from scratch is a monumental task. It necessitates defining a query interface for handling the database and implementing a corresponding parser. Moreover, a separate execution layer for running operations must be built. Also, the planning layer, which is responsible for devising execution strategies, is a vital aspect of this process. Let's not forget about the critical storage layer that physically reads and stores the data. In a nutshell, there's a daunting amount of work involved in developing a new database."),(0,i.yg)("p",null,"Given these circumstances, it's understandable why numerous emerging databases resort to high pricing structures\u2014they need immediate revenue to offset continuous development costs."),(0,i.yg)("p",null,"But the story doesn't end here. Query interfaces like SQL are indeed useful for serious tasks, but they also provide excellent utility for handling simple log files such as CSV, JSONL, Parquet, and even for utilizing REST APIs for various applications. The issue arises when a complex query interface needs to be provided even for these lighter storage requirements\u2014it necessitates a development process almost identical to building a sophisticated database. Implementing an entire parser and execution layer just to add SQL support to an existing service can seem like an excessive burden."),(0,i.yg)("p",null,"Whether it's a simple storage environment or a serious task, the key lies in the storage layer, which involves the actual reading and storing of data. So, what if developers focused on implementing these storage mechanisms while the remaining parts could be handled using existing libraries? This is the role that GlueSQL aspires to play."),(0,i.yg)("h2",{id:"the-vision-of-gluesql"},"The Vision of GlueSQL"),(0,i.yg)("p",null,"The GlueSQL project aims to offer a unified query interface for various environments. The goal is to allow anyone to port and use SQL and GlueSQL's proprietary query builder, the AST Builder, in any desired environment. This could range from key-value databases, serious NoSQL databases, log files, and even REST API services. Essentially, if a service supports reading or read-writing data, regardless of the data type, it can readily support a complex query interface via GlueSQL."),(0,i.yg)("p",null,"Presently, the GlueSQL project itself directly supports a few storage types as reference storages. These include in-memory storage for non-persistent data handling, sled storage, which is a key-value database written in Rust, JSON storage for handling JSON and JSONL files, and a storage that ports SQL to the web browser's IndexedDB. While the GlueSQL Team is primarily developing these, the aim is to allow anyone to create such custom storages for a wide array of purposes, thus enabling them to assemble the database of their choosing."),(0,i.yg)("p",null,"Imagine using GlueSQL's SQL and AST Builder everywhere, with the simple method of swapping out storages to operate in diverse settings. It could significantly reduce software development costs. Developers wouldn't need to learn the different usage methods for each database. Instead, they could focus solely on implementing business logic using the same interface."),(0,i.yg)("p",null,"Our vision is to reduce database development costs by 10 times, or even more than 20 times. We aim to gather diverse database creators under the GlueSQL banner, making it the go-to solution for cost-effective database development."),(0,i.yg)("h2",{id:"benefits-to-database-users-unifying-query-interfaces-streamlining-software-development-and-reducing-costs"},"Benefits to Database Users: Unifying Query Interfaces, Streamlining Software Development, and Reducing Costs"),(0,i.yg)("p",null,"From the perspective of the users who engage with databases, there has always been the burden of learning different interfaces to interact with each database. The approach required to work with Redis is different from that necessary for MongoDB. Likewise, handling SQL databases necessitates using SQL. Although SQL databases generally use a common SQL, the SQL they support can considerably vary when examined in detail."),(0,i.yg)("p",null,"Naturally, there are legitimate reasons for such differences. Each database focuses on different areas, and to cater to specialized functionalities, they incorporate dedicated interface mechanisms. However, not all application development needs to utilize these database-specific core special functionalities."),(0,i.yg)("p",null,"Let's look at a couple of examples:"),(0,i.yg)("p",null,"Suppose you're developing a back-end application that uses MySQL as the database and Redis for caching. Due to the vast differences in handling SQL databases and Redis, you would have to develop using different methods when storing data."),(0,i.yg)("p",null,"Here's another scenario:\nImagine you're implementing a data migration pipeline between various databases and log files. Let's say you're transferring Parquet to Redis or MongoDB. In this case, you would need to convert data using different methods for each, all of which would be a cumbersome process."),(0,i.yg)("p",null,"In both of the above examples, GlueSQL can directly address and solve the issues. It offers the convenience of a uniform query interface to deal with these matters. In certain scenarios, even the construction of a data pipeline can potentially be solved with a single SQL query, thanks to GlueSQL."),(0,i.yg)("h2",{id:"benefits-to-database-developers-drastically-lowering-development-costs-and-simplifying-the-creation-of-purpose-built-databases"},"Benefits to Database Developers: Drastically Lowering Development Costs and Simplifying the Creation of Purpose-Built Databases"),(0,i.yg)("p",null,"If you want to support SQL in the desired environment, using GlueSQL essentially requires you to implement an interface for Storage. There's no need to support all functionalities from the beginning. You can start lightly, choosing and implementing storage features suitable for the environment you want to create. To facilitate this, GlueSQL also provides a library in the form of a test suite to easily validate the storage you've implemented."),(0,i.yg)("p",null,"Lowering development costs in this way will enable a broader range of developers to support the GlueSQL query interface. As more developers join, a significant synergy can be generated. Designing a query interface from scratch involves a great deal of work, including planning and supporting the interface for different target programming languages."),(0,i.yg)("p",null,"However, despite all this hard work, it is not easy to attract database users accustomed to different methods."),(0,i.yg)("p",null,"Consider that the SQL and AST Builder provided by GlueSQL are already securing numerous users. This eliminates the need for efforts to promote a newly planned query interface. Over the years, many new databases have emphasized compatibility with PostgreSQL or MySQL for similar reasons. As GlueSQL places a strong emphasis on portability in its query interface planning, it allows for more flexible configuration according to the desired situation. Through the AST Builder, it also eliminates the cost of porting to different languages."),(0,i.yg)("p",null,"For many database developers, using GlueSQL can be an optimal choice, as it can save costs and quickly secure users."),(0,i.yg)("p",null,"Let me mention one more thing: what's convenient for humans... could be applied to AI as well. Rather than making AI write automation code using different databases, providing a common query interface can be much more efficient."),(0,i.yg)("h2",{id:"the-future-with-gluesql"},"The Future with GlueSQL"),(0,i.yg)("p",null,"GlueSQL has been and will continue to improve and develop new features to enable portability in various environments. Thanks to the schemaless data support added last year, it is now possible to handle both structured data with schema and unstructured data like JSON simultaneously. This has significantly increased the range of storage environments that can be supported."),(0,i.yg)("p",null,"One of the key features added last year was the AST Builder. This feature allowed us to escape the confines of SQL and provide an interface for comfortably handling data in the programming languages used for development."),(0,i.yg)("p",null,"Of course, improving existing features is extremely important, and there are many new features to be added. As a major development plan this year, we aim to develop features to effectively attach GlueSQL to NoSQL databases with their own planners and execution layers. The GlueSQL query planner, currently at a basic level, will see significant changes this year. With the expansion of this planner, not only NoSQL databases but also other SQL databases could be supported without sacrificing performance using GlueSQL."),(0,i.yg)("p",null,"The synergy that arises from the combination of different databases is a significant bonus in this process."),(0,i.yg)("h2",{id:"the-journey-of-the-gluesql-team"},"The Journey of the GlueSQL Team"),(0,i.yg)("p",null,"The GlueSQL project was first conceived in the fall of 2019, and since then we have been developing it continuously. Personally, I have created various products in a variety of environments, including game development, backend server, and frontend development over the past decade. The experience gained through this process was a major motivation to start the GlueSQL project."),(0,i.yg)("p",null,"To put it grandly, the inconveniences felt while using different databases in various environments were a major motivation, wouldn't you say?"),(0,i.yg)("p",null,"The start was actually a bit simple. Around 2019, I was mainly doing web front-end development. However, the lack of a structured database for state management and internal data processing made it very uncomfortable, especially since I couldn't use SQL databases and the like. So I started to lightly create an SQL database that could run on a web browser. Also, I wanted to use Rust, but after failing to introduce it at the company I was working for at the time, I decided to use it in my own project."),(0,i.yg)("p",null,'But as I started developing, my dreams grew significantly. Beyond a SQL database that simply operates on a web browser, I started envisioning a database that fits the name "Glue", one that can easily be ported to various environments, and I continue that journey to this day.'),(0,i.yg)("p",null,"Whether I took the database project too lightly, or because the features I wanted kept increasing, the content to be developed kept expanding. As a result, I ended up investing full time in the GlueSQL project development for over three years. For a year in between, I even juggled full-time software engineering work alongside GlueSQL development. Currently, I'm back to developing the GlueSQL project full time, alongside various part-time contributors."),(0,i.yg)("p",null,"Now, we're getting very close to the starting point of the picture I wanted to create through GlueSQL, and thankfully, with contributors joining me, I am not alone."),(0,i.yg)("h2",{id:"the-sustainability-and-business-aspect-of-gluesql"},"The Sustainability and Business Aspect of GlueSQL"),(0,i.yg)("p",null,"I believe that what we create through GlueSQL will make a great contribution to the world and make many software engineers happy. This gives me immense strength to continue developing even in difficult situations. However, we cannot accomplish everything with pure passion alone. As much as the GlueSQL project can make a significant contribution, I also see it as holding great business value."),(0,i.yg)("p",null,"The business strategy of GlueSQL may be somewhat different from other databases. We distribute the project itself as open source under the Apache-2.0 license, so that anyone can use it fully, and we do not consider pricing methods such as restricting features to the storages we support. In fact, if there is any player who can do it better, there's no way to prevent them from taking the GlueSQL project and making it their own."),(0,i.yg)("p",null,"But we believe that GlueSQL has great potential in this regard. Anyone can participate and they are free to distribute their own storage in the way they want, whether it's open source, private, or commercial. This eliminates the need to create something to replace the GlueSQL project. We aim to prevent the need to recreate the wheel that we provide using GlueSQL."),(0,i.yg)("p",null,"Moreover, our GlueSQL team seeks to continually expand our group of developers and companies working with us. During this development process, while they can certainly implement everything on their own, there is also no reason not to collaborate with our GlueSQL Team, especially for databases like NoSQL that have their own planners and execution layers. If you have a REST API and want to enhance convenience through SQL support, you can do it yourself or you can collaborate with us."),(0,i.yg)("p",null,"In addition, for some storages, we can also participate as players in the same position as other custom storage developers. We plan to expand the GlueSQL ecosystem in various ways, such as technical support and storage development."),(0,i.yg)("p",null,"We are finally ready to provide GlueSQL to users at the production level. We are accelerating the development of GlueSQL. If you are a company interested in storage development like SQL support, or if you resonate with our vision and want to join us, please contact us at ",(0,i.yg)("a",{parentName:"p",href:"mailto:taehoon@gluesql.com"},"taehoon@gluesql.com"),"."),(0,i.yg)("h2",{id:"conclusion"},"Conclusion"),(0,i.yg)("p",null,"The continued emergence of new databases is driven by the demand for diverse and specialized databases, such as those optimized for Large Language Models (LLMs) and databases catering to unique requirements, like embedded databases, OLAP, OLTP, and time-series data processing. However, developing a new database from scratch is a significant undertaking, requiring extensive work, which often results in high costs."),(0,i.yg)("p",null,"GlueSQL presents a solution to this challenge by providing a unified query interface that can be ported across various environments, from key-value databases, NoSQL databases, log files, to REST APIs. It allows anyone to create custom storages, reducing the need for developers to build entirely new databases and to learn different usage methods for each database. Instead, they can focus on implementing their business logic using the same interface."),(0,i.yg)("p",null,"From a user perspective, GlueSQL offers the convenience of a unified query interface, easing the burden of learning different interfaces for each database. This simplification of interface use can also extend to AI, potentially enhancing the efficiency of AI automation."),(0,i.yg)("p",null,"GlueSQL's development plan includes significant enhancements to its query planner and aims to enable effective attachment of GlueSQL to NoSQL databases. The synergy of combining different databases is a valuable bonus in this process."),(0,i.yg)("p",null,"Since its inception in the fall of 2019, the GlueSQL team has continuously developed the project, driven by the desire to mitigate the inconveniences encountered while using different databases in various environments. The journey has been a rewarding one, with the GlueSQL project now at a point where it closely resembles the envisioned product."),(0,i.yg)("p",null,"GlueSQL, distributed under the Apache-2.0 license, is free for anyone to use and adapt. While the GlueSQL team welcomes collaboration with other developers and companies, they also see significant potential for the project as a business venture. The team is working to expand the GlueSQL ecosystem through a variety of initiatives, including technical support and storage development."),(0,i.yg)("p",null,"With GlueSQL now sufficiently prepared for practical applications, the team invites companies interested in storage development or those who share their vision to join them in their journey of revolutionizing database development."))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/2149662b.86af6d60.js b/docs/0.16.0/assets/js/2149662b.86af6d60.js new file mode 100644 index 00000000..c3d02428 --- /dev/null +++ b/docs/0.16.0/assets/js/2149662b.86af6d60.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[1553],{8125:s=>{s.exports=JSON.parse('{"permalink":"/docs/0.16.0/blog/tags/tdd","page":1,"postsPerPage":10,"totalPages":1,"totalCount":1,"blogDescription":"Blog","blogTitle":"Blog"}')}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/234733fd.413dbe85.js b/docs/0.16.0/assets/js/234733fd.413dbe85.js new file mode 100644 index 00000000..5bb57847 --- /dev/null +++ b/docs/0.16.0/assets/js/234733fd.413dbe85.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[8053],{5680:(e,t,a)=>{a.d(t,{xA:()=>o,yg:()=>c});var l=a(6540);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function n(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);t&&(l=l.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,l)}return a}function i(e){for(var t=1;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);for(l=0;l=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var p=l.createContext({}),u=function(e){var t=l.useContext(p),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},o=function(e){var t=u(e.components);return l.createElement(p.Provider,{value:t},e.children)},h="mdxType",s={inlineCode:"code",wrapper:function(e){var t=e.children;return l.createElement(l.Fragment,{},t)}},m=l.forwardRef((function(e,t){var a=e.components,r=e.mdxType,n=e.originalType,p=e.parentName,o=g(e,["components","mdxType","originalType","parentName"]),h=u(a),m=r,c=h["".concat(p,".").concat(m)]||h[m]||s[m]||n;return a?l.createElement(c,i(i({ref:t},o),{},{components:a})):l.createElement(c,i({ref:t},o))}));function c(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var n=a.length,i=new Array(n);i[0]=m;var g={};for(var p in t)hasOwnProperty.call(t,p)&&(g[p]=t[p]);g.originalType=e,g[h]="string"==typeof e?e:r,i[1]=g;for(var u=2;u{a.r(t),a.d(t,{assets:()=>p,contentTitle:()=>i,default:()=>s,frontMatter:()=>n,metadata:()=>g,toc:()=>u});var l=a(8168),r=(a(6540),a(5680));const n={title:"Release v0.14",description:"Release Note - v0.14",slug:"release-v0.14",authors:[{name:"Taehoon Moon",title:"Creator of GlueSQL",url:"https://github.com/panarch",image_url:"https://github.com/panarch.png"}],tags:["v0.14","release-note"]},i=void 0,g={permalink:"/docs/0.16.0/blog/release-v0.14",source:"@site/blog/2023-05-27-release-v0.14.md",title:"Release v0.14",description:"Release Note - v0.14",date:"2023-05-27T00:00:00.000Z",formattedDate:"May 27, 2023",tags:[{label:"v0.14",permalink:"/docs/0.16.0/blog/tags/v-0-14"},{label:"release-note",permalink:"/docs/0.16.0/blog/tags/release-note"}],readingTime:10.24,hasTruncateMarker:!1,authors:[{name:"Taehoon Moon",title:"Creator of GlueSQL",url:"https://github.com/panarch",image_url:"https://github.com/panarch.png",imageURL:"https://github.com/panarch.png"}],frontMatter:{title:"Release v0.14",description:"Release Note - v0.14",slug:"release-v0.14",authors:[{name:"Taehoon Moon",title:"Creator of GlueSQL",url:"https://github.com/panarch",image_url:"https://github.com/panarch.png",imageURL:"https://github.com/panarch.png"}],tags:["v0.14","release-note"]},prevItem:{title:"Breaking the Boundary between SQL and NoSQL Databases",permalink:"/docs/0.16.0/blog/breaking-the-boundary-between-sql-and-nosql"}},p={authorsImageUrls:[void 0]},u=[{value:"\ud83d\ude80 Features",id:"-features",level:2},{value:"\ud83c\udf40 Schemaless data support",id:"-schemaless-data-support",level:3},{value:"\ud83c\udf40 IndexedDB & WebStorage supports in JavaScript package",id:"-indexeddb--webstorage-supports-in-javascript-package",level:3},{value:"\ud83c\udf40 Data Types - UINT32, UINT64, UINT128, POINT and FLOAT32",id:"-data-types---uint32-uint64-uint128-point-and-float32",level:3},{value:"\ud83c\udf40 Functions - APPEND, PREPEND, RAND, FIND_IDX, INITCAP and CALC_DISTANCE",id:"-functions---append-prepend-rand-find_idx-initcap-and-calc_distance",level:3},{value:"\ud83c\udf40 Store traits",id:"-store-traits",level:3},{value:"User-level custom function",id:"user-level-custom-function",level:4},{value:"Metadata",id:"metadata",level:4},{value:"\ud83c\udf40 Storages",id:"-storages",level:3},{value:"JSON Storage",id:"json-storage",level:4},{value:"Composite Storage",id:"composite-storage",level:4},{value:"IndexedDB Storage",id:"indexeddb-storage",level:4},{value:"Web Storage",id:"web-storage",level:4},{value:"\ud83c\udf40 Other new features",id:"-other-new-features",level:3},{value:"\ud83c\udf0a Interface Changes",id:"-interface-changes",level:2},{value:"\ud83c\udf1f Improvements",id:"-improvements",level:2},{value:"\ud83c\udf33 Documentation",id:"-documentation",level:2},{value:"Docs - setup",id:"docs---setup",level:3},{value:"\ud83d\udccb Tests",id:"-tests",level:2},{value:"\ud83d\udc1b Bug Fixes",id:"-bug-fixes",level:2}],o={toc:u},h="wrapper";function s(e){let{components:t,...a}=e;return(0,r.yg)(h,(0,l.A)({},o,a,{components:t,mdxType:"MDXLayout"}),(0,r.yg)("p",null,"We now provide an official documentation website at ",(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"https://gluesql.org/docs"},"https://gluesql.org/docs"))),(0,r.yg)("h2",{id:"-features"},"\ud83d\ude80 Features"),(0,r.yg)("h3",{id:"-schemaless-data-support"},"\ud83c\udf40 Schemaless data support"),(0,r.yg)("p",null,"GlueSQL now supports creating tables without a schema, allowing for both structured and unstructured data to be stored in the same table.\nTo create a schemaless table, simply run CREATE TABLE without specifying any columns. For more information on querying schemaless data, please refer to the following link: ",(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"https://gluesql.org/docs/dev/sql-syntax/statements/querying/schemaless"},"querying schemaless data"))),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE Bar;\n")),(0,r.yg)("p",null,"To insert values,"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},'INSERT INTO Bar VALUES\n (\'{ "name": "ast", "value": 30 }\'),\n (\'{ "name": "glue", "rate": 3.0, "list": [1, 2, 3] }\'),\n')),(0,r.yg)("p",null,"Then, selecting values from schemaless table is simple."),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT name, rate, list[0] FROM Bar WHERE name = 'glue';\n")),(0,r.yg)("p",null,"e.g."),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},'CREATE TABLE Names (id INTEGER, name TEXT);\nINSERT INTO Names VALUES (1, \'glue\'), (2, \'sql\');\n\nCREATE TABLE Logs;\nINSERT INTO Logs VALUES\n (\'{ "id": 1, "value": 30 }\'),\n (\'{ "id": 2, "rate": 3.0, "list": [1, 2, 3] }\'),\n (\'{ "id": 3, "rate": 5.0, "value": 100 }\');\n\nSELECT * FROM Names JOIN Logs ON Names.id = Logs.id;\n/*\n| id | list | name | rate | value |\n|----|---------|------|------|-------|\n| 1 | | glue | | 30 |\n| 2 |[1, 2, 3]| sql | 3 | |\n*/\n')),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Schemaless data support ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1046"},"#1046"),")")),(0,r.yg)("h3",{id:"-indexeddb--webstorage-supports-in-javascript-package"},"\ud83c\udf40 IndexedDB & WebStorage supports in JavaScript package"),(0,r.yg)("p",null,"GlueSQL supports handling in-memory, localStorage, sessionStorage, and even IndexedDB using the same SQL syntax. All you need to know is how to specify the ",(0,r.yg)("inlineCode",{parentName:"p"},"ENGINE")," when creating a table."),(0,r.yg)("p",null,"e.g."),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE Mem (mid INTEGER) ENGINE = memory;\nCREATE TABLE Loc (lid INTEGER) ENGINE = localStorage;\nCREATE TABLE Ses (sid INTEGER) ENGINE = sessionStorage;\nCREATE TABLE Idb (iid INTEGER) ENGINE = indexedDB;\n\nSELECT\n mid, lid, sid, iid \nFROM Mem\nJOIN Loc\nJOIN Ses\nJOIN Idb;\n")),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Apply CompositeStorage to JS package ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1084"},"#1084"),")")),(0,r.yg)("h3",{id:"-data-types---uint32-uint64-uint128-point-and-float32"},"\ud83c\udf40 Data Types - ",(0,r.yg)("inlineCode",{parentName:"h3"},"UINT32"),", ",(0,r.yg)("inlineCode",{parentName:"h3"},"UINT64"),", ",(0,r.yg)("inlineCode",{parentName:"h3"},"UINT128"),", ",(0,r.yg)("inlineCode",{parentName:"h3"},"POINT")," and ",(0,r.yg)("inlineCode",{parentName:"h3"},"FLOAT32")),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"implement f32 data type ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/pythonbrad"},"@pythonbrad")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1145"},"#1145"),")"),(0,r.yg)("li",{parentName:"ul"},"Implement geometric ",(0,r.yg)("inlineCode",{parentName:"li"},"POINT")," Type and geometric functions ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/seonghun-dev"},"@seonghun-dev")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1048"},"#1048"),")"),(0,r.yg)("li",{parentName:"ul"},"Add ",(0,r.yg)("inlineCode",{parentName:"li"},"UINT32"),", ",(0,r.yg)("inlineCode",{parentName:"li"},"UINT64")," and ",(0,r.yg)("inlineCode",{parentName:"li"},"UINT128")," data types ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ChobobDev"},"@ChobobDev")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1019"},"#1019"),")"),(0,r.yg)("li",{parentName:"ul"},"Add inet datatype ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/pythonbrad"},"@pythonbrad")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1080"},"#1080"),")")),(0,r.yg)("h3",{id:"-functions---append-prepend-rand-find_idx-initcap-and-calc_distance"},"\ud83c\udf40 Functions - ",(0,r.yg)("inlineCode",{parentName:"h3"},"APPEND"),", ",(0,r.yg)("inlineCode",{parentName:"h3"},"PREPEND"),", ",(0,r.yg)("inlineCode",{parentName:"h3"},"RAND"),", ",(0,r.yg)("inlineCode",{parentName:"h3"},"FIND_IDX"),", ",(0,r.yg)("inlineCode",{parentName:"h3"},"INITCAP")," and ",(0,r.yg)("inlineCode",{parentName:"h3"},"CALC_DISTANCE")),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Feat : add calc","_","distance function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/seonghun-dev"},"@seonghun-dev")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1153"},"#1153"),")"),(0,r.yg)("li",{parentName:"ul"},"Add ",(0,r.yg)("inlineCode",{parentName:"li"},"PREPEND")," function for ",(0,r.yg)("inlineCode",{parentName:"li"},"LIST")," data type ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/seonghun-dev"},"@seonghun-dev")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1149"},"#1149"),")"),(0,r.yg)("li",{parentName:"ul"},"add initcap function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/pythonbrad"},"@pythonbrad")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1064"},"#1064"),")"),(0,r.yg)("li",{parentName:"ul"},"Implement ",(0,r.yg)("inlineCode",{parentName:"li"},"FIND_IDX")," function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/zmrdltl"},"@zmrdltl")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1100"},"#1100"),")"),(0,r.yg)("li",{parentName:"ul"},"Implement Rand function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/pythonbrad"},"@pythonbrad")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1063"},"#1063"),")"),(0,r.yg)("li",{parentName:"ul"},"Add Append Function to LIST DataType ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/seonghun-dev"},"@seonghun-dev")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1047"},"#1047"),")")),(0,r.yg)("h3",{id:"-store-traits"},"\ud83c\udf40 Store traits"),(0,r.yg)("h4",{id:"user-level-custom-function"},"User-level custom function"),(0,r.yg)("p",null,"By implementing both the CustomFunction and CustomFunctionMut traits, users can create, use, and delete user-level custom functions. Although GlueSQL plans to continuously add various functions, users may still find them insufficient. In such cases, users can create their own user-level custom functions to supplement the built-in functions. Additionally, if there are repetitive business logic codes, they can be stored as custom functions.\ne.g."),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE FUNCTION ADD_ONE (n INT, x INT DEFAULT 1) RETURN n + x;\n\nSELECT ADD_ONE(10) AS test;\n\nDROP FUNCTION ADD_ONE;\n")),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Support user level sql function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/pythonbrad"},"@pythonbrad")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1095"},"#1095"),")")),(0,r.yg)("h4",{id:"metadata"},"Metadata"),(0,r.yg)("p",null,"The Metadata trait is an optional implementation for providing additional metadata support in GlueSQL. GlueSQL does not enforce any specific metadata implementation, allowing custom storage developers to decide which type of metadata, such as create time, modify time, etc., they want to provide."),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Support Metadata trait ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1096"},"#1096"),")")),(0,r.yg)("h3",{id:"-storages"},"\ud83c\udf40 Storages"),(0,r.yg)("h4",{id:"json-storage"},"JSON Storage"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Add JsonStorage support to CLI ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1135"},"#1135"),")"),(0,r.yg)("li",{parentName:"ul"},"Rename ",(0,r.yg)("inlineCode",{parentName:"li"},"Jsonl"),"Storage to ",(0,r.yg)("inlineCode",{parentName:"li"},"Json"),"Storage ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1128"},"#1128"),")"),(0,r.yg)("li",{parentName:"ul"},"Support ",(0,r.yg)("inlineCode",{parentName:"li"},"JSON")," format in ",(0,r.yg)("inlineCode",{parentName:"li"},"JSONL storage")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1123"},"#1123"),")"),(0,r.yg)("li",{parentName:"ul"},"Support ",(0,r.yg)("inlineCode",{parentName:"li"},"Jsonl")," Storage ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1053"},"#1053"),")")),(0,r.yg)("h4",{id:"composite-storage"},"Composite Storage"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Add CompositeStorage which bundles multiple storages ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1068"},"#1068"),")")),(0,r.yg)("h4",{id:"indexeddb-storage"},"IndexedDB Storage"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Add IndexedDB storage support ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1067"},"#1067"),")")),(0,r.yg)("h4",{id:"web-storage"},"Web Storage"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Add WebStorage - support localStorage \\& sessionStorage for web browsers ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1050"},"#1050"),")")),(0,r.yg)("h3",{id:"-other-new-features"},"\ud83c\udf40 Other new features"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Wrap identifiers with double quote (",(0,r.yg)("inlineCode",{parentName:"li"},'"'),") at ",(0,r.yg)("inlineCode",{parentName:"li"},"to_sql")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1130"},"#1130"),")"),(0,r.yg)("li",{parentName:"ul"},"Support Values Query at ASTBuilder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1041"},"#1041"),")"),(0,r.yg)("li",{parentName:"ul"},"Support ",(0,r.yg)("inlineCode",{parentName:"li"},"Schema::from_ddl(ddl: &str) -> String")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1089"},"#1089"),")"),(0,r.yg)("li",{parentName:"ul"},"Support column alias for Table, Derived Table ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ding-young"},"@ding-young")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1065"},"#1065"),")"),(0,r.yg)("li",{parentName:"ul"},"Support ",(0,r.yg)("inlineCode",{parentName:"li"},"TableFactor::{Derived, Dictionary, Series}")," in AstBuilder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1007"},"#1007"),")")),(0,r.yg)("h2",{id:"-interface-changes"},"\ud83c\udf0a Interface Changes"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Remove Store trait related cfg features, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1091"},"#1091"),")"),(0,r.yg)("li",{parentName:"ul"},"Refactor CreateTable.columns from ",(0,r.yg)("inlineCode",{parentName:"li"},"Vec")," to ",(0,r.yg)("inlineCode",{parentName:"li"},"Option>")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1086"},"#1086"),")"),(0,r.yg)("li",{parentName:"ul"},"Remove ",(0,r.yg)("inlineCode",{parentName:"li"},"MutResult")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1073"},"#1073"),")"),(0,r.yg)("li",{parentName:"ul"},"Update all store mut trait methods to take \\&mut self ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1072"},"#1072"),")"),(0,r.yg)("li",{parentName:"ul"},"Change StoreMut interface to use \\&mut self, not to take ownership ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1071"},"#1071"),")"),(0,r.yg)("li",{parentName:"ul"},"Modify default ColumnOption from NOT NULL to NULL ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/997"},"#997"),")")),(0,r.yg)("h2",{id:"-improvements"},"\ud83c\udf1f Improvements"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Add a case for insert with source ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1211"},"#1211"),")"),(0,r.yg)("li",{parentName:"ul"},"Apply workspace inheritance to remaining Cargo.toml in storages/, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1181"},"#1181"),")"),(0,r.yg)("li",{parentName:"ul"},"Add nullable, key, default to ",(0,r.yg)("inlineCode",{parentName:"li"},"GLUE_TABLE_COLUMNS")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1177"},"#1177"),")"),(0,r.yg)("li",{parentName:"ul"},"Update core to bundle all errors using error module, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1178"},"#1178"),")"),(0,r.yg)("li",{parentName:"ul"},"Update global Error enum to display with error module prefix ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1175"},"#1175"),")"),(0,r.yg)("li",{parentName:"ul"},"fix: typo ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1161"},"#1161"),")"),(0,r.yg)("li",{parentName:"ul"},"Move the SCHEMA","_","PREFIX const into an impl in SledStorage ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/garypen"},"@garypen")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1151"},"#1151"),")"),(0,r.yg)("li",{parentName:"ul"},"Merge evaluate","_","stateless into evaluate, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1132"},"#1132"),")"),(0,r.yg)("li",{parentName:"ul"},"Remove memory-storage dep from JsonStorage/ Cargo.toml ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1131"},"#1131"),")"),(0,r.yg)("li",{parentName:"ul"},"Simplify JsonlStorage codes ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1126"},"#1126"),")"),(0,r.yg)("li",{parentName:"ul"},"Bump rust version to 1.68 ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1125"},"#1125"),")"),(0,r.yg)("li",{parentName:"ul"},"Keep ",(0,r.yg)("inlineCode",{parentName:"li"},"Cargo.lock")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1121"},"#1121"),")"),(0,r.yg)("li",{parentName:"ul"},"Replace closure to variable in ",(0,r.yg)("inlineCode",{parentName:"li"},"data/interval")," module ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1118"},"#1118"),")"),(0,r.yg)("li",{parentName:"ul"},"Add ",(0,r.yg)("inlineCode",{parentName:"li"},"f64")," support to ",(0,r.yg)("inlineCode",{parentName:"li"},"data::Key")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1114"},"#1114"),")"),(0,r.yg)("li",{parentName:"ul"},"Add Ord impl for Key, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1110"},"#1110"),")"),(0,r.yg)("li",{parentName:"ul"},"join","_","expr when in","_","subquery, exists expr in join constraint ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ding-young"},"@ding-young")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1112"},"#1112"),")"),(0,r.yg)("li",{parentName:"ul"},"Split JS related GitHub action, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1109"},"#1109"),")"),(0,r.yg)("li",{parentName:"ul"},"Fix error handling for ",(0,r.yg)("inlineCode",{parentName:"li"},"ilike")," function on ",(0,r.yg)("inlineCode",{parentName:"li"},"Literal")," being treated as\u2026 ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1107"},"#1107"),")"),(0,r.yg)("li",{parentName:"ul"},"Remove ",(0,r.yg)("inlineCode",{parentName:"li"},"Rc")," in ",(0,r.yg)("inlineCode",{parentName:"li"},"validate.rs")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1106"},"#1106"),")"),(0,r.yg)("li",{parentName:"ul"},"Remove ",(0,r.yg)("inlineCode",{parentName:"li"},"Error::Storage")," variant ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1105"},"#1105"),")"),(0,r.yg)("li",{parentName:"ul"},"Replace ",(0,r.yg)("inlineCode",{parentName:"li"},"Box::pin")," to ",(0,r.yg)("inlineCode",{parentName:"li"},"futures_enum::Stream")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1103"},"#1103"),")"),(0,r.yg)("li",{parentName:"ul"},"Remove stream unneeded map ok uses ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1104"},"#1104"),")"),(0,r.yg)("li",{parentName:"ul"},"Replace ",(0,r.yg)("inlineCode",{parentName:"li"},"TryStream")," to ",(0,r.yg)("inlineCode",{parentName:"li"},"Stream")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1102"},"#1102"),")"),(0,r.yg)("li",{parentName:"ul"},"Remove ",(0,r.yg)("inlineCode",{parentName:"li"},"Rc")," from ",(0,r.yg)("inlineCode",{parentName:"li"},"ColumnValidation")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1101"},"#1101"),")"),(0,r.yg)("li",{parentName:"ul"},"Remove unneeded Rc uses in fetch","_","labels ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1098"},"#1098"),")"),(0,r.yg)("li",{parentName:"ul"},"Simplify TryStreamExt using codes in join executor, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1097"},"#1097"),")"),(0,r.yg)("li",{parentName:"ul"},"Fix typo in plan/validate.rs ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1093"},"#1093"),")"),(0,r.yg)("li",{parentName:"ul"},"Update IdbStorage to use Schema::{to","_","ddl, from","_","ddl} to manage schema \u2026 ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1090"},"#1090"),")"),(0,r.yg)("li",{parentName:"ul"},"Update Cargo.toml files to inherit workspace level configs, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1088"},"#1088"),")"),(0,r.yg)("li",{parentName:"ul"},"Add Error enum to core::prelude ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1087"},"#1087"),")"),(0,r.yg)("li",{parentName:"ul"},"Update ",(0,r.yg)("inlineCode",{parentName:"li"},"StringExt")," implementation to use ",(0,r.yg)("inlineCode",{parentName:"li"},"str")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1082"},"#1082"),")"),(0,r.yg)("li",{parentName:"ul"},"Add enum ",(0,r.yg)("inlineCode",{parentName:"li"},"StrSlice")," under enum ",(0,r.yg)("inlineCode",{parentName:"li"},"Evaluated")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/zmrdltl"},"@zmrdltl")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/999"},"#999"),")"),(0,r.yg)("li",{parentName:"ul"},"refactor plan::validate::Context.labels from String to str ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1079"},"#1079"),")"),(0,r.yg)("li",{parentName:"ul"},"Replace ",(0,r.yg)("inlineCode",{parentName:"li"},"dyn object")," to generic ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1075"},"#1075"),")"),(0,r.yg)("li",{parentName:"ul"},"Implement ValidationContext(schema","_","map + alias) to enhance validation of ambiguous columns ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/883"},"#883"),")"),(0,r.yg)("li",{parentName:"ul"},"Remove ",(0,r.yg)("inlineCode",{parentName:"li"},"clone")," in ",(0,r.yg)("inlineCode",{parentName:"li"},"check_table_factor")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1058"},"#1058"),")"),(0,r.yg)("li",{parentName:"ul"},"Bump rust-toolchain version to ",(0,r.yg)("inlineCode",{parentName:"li"},"1.66")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1057"},"#1057"),")"),(0,r.yg)("li",{parentName:"ul"},"Bump ",(0,r.yg)("inlineCode",{parentName:"li"},"sqlparser")," version to ",(0,r.yg)("inlineCode",{parentName:"li"},"0.30")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1056"},"#1056"),")"),(0,r.yg)("li",{parentName:"ul"},"Replace ",(0,r.yg)("inlineCode",{parentName:"li"},"Box::pin")," to ",(0,r.yg)("inlineCode",{parentName:"li"},"futures_enum")," in aggregate module ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1055"},"#1055"),")"),(0,r.yg)("li",{parentName:"ul"},"Update js/ Cargo.toml to use gloo-utils for serde handling ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1049"},"#1049"),")"),(0,r.yg)("li",{parentName:"ul"},"Remove ast::ColumnOption and merge UNIQUE option to ColumnDef ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1044"},"#1044"),")"),(0,r.yg)("li",{parentName:"ul"},"Rewrite \\& simplify plan/context.rs codes, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1045"},"#1045"),")"),(0,r.yg)("li",{parentName:"ul"},"Move ast::ColumnOption::Default variant to ColumnDef ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1042"},"#1042"),")"),(0,r.yg)("li",{parentName:"ul"},"[AST-Builder]"," Remove unused prebuild nodes ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ding-young"},"@ding-young")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1043"},"#1043"),")"),(0,r.yg)("li",{parentName:"ul"},"Remove data::RowError, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1040"},"#1040"),")"),(0,r.yg)("li",{parentName:"ul"},"Reorder project in ASTBuilder (project -> ordery","_","by -> limit,offset) ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1039"},"#1039"),")"),(0,r.yg)("li",{parentName:"ul"},"Remove unused LimitOffsetNode in AST builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1038"},"#1038"),")"),(0,r.yg)("li",{parentName:"ul"},"Rename executor/ blend.rs module to project.rs ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/SaumyaBhushan"},"@SaumyaBhushan")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1036"},"#1036"),")"),(0,r.yg)("li",{parentName:"ul"},"Add Debug to AST builder nodes ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1022"},"#1022"),")"),(0,r.yg)("li",{parentName:"ul"},"Bump rust toolchain version to 1.65 ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1035"},"#1035"),")"),(0,r.yg)("li",{parentName:"ul"},"Remove ",(0,r.yg)("inlineCode",{parentName:"li"},"Content::Shared")," variant in executor/ ",(0,r.yg)("inlineCode",{parentName:"li"},"RowContext")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1032"},"#1032"),")"),(0,r.yg)("li",{parentName:"ul"},"Merge insert logics in row.rs \\& execute.rs into executor/insert.rs ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1031"},"#1031"),")"),(0,r.yg)("li",{parentName:"ul"},"Merge FilterContext and BlendContext into RowContext ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1029"},"#1029"),")"),(0,r.yg)("li",{parentName:"ul"},"Update ",(0,r.yg)("inlineCode",{parentName:"li"},"data::Row")," to contain columns ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1026"},"#1026"),")"),(0,r.yg)("li",{parentName:"ul"},"Add LIST type support in CONCAT function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/seonghun-dev"},"@seonghun-dev")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1021"},"#1021"),")"),(0,r.yg)("li",{parentName:"ul"},"Remove LimitOffsetNode in AST builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1023"},"#1023"),")"),(0,r.yg)("li",{parentName:"ul"},"Fix typo ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1020"},"#1020"),")"),(0,r.yg)("li",{parentName:"ul"},"Add NumericNode to handle numeric value inputs in AST builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1017"},"#1017"),")"),(0,r.yg)("li",{parentName:"ul"},"Update ValueError::InvalidJsonString error to show input text ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1018"},"#1018"),")"),(0,r.yg)("li",{parentName:"ul"},"Add null() func which makes NULL value in AST builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1016"},"#1016"),")"),(0,r.yg)("li",{parentName:"ul"},"Add --all-targets option to cargo clippy rust gh-action ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1015"},"#1015"),")"),(0,r.yg)("li",{parentName:"ul"},"Move import ",(0,r.yg)("inlineCode",{parentName:"li"},"ColumnOption")," used only by ",(0,r.yg)("inlineCode",{parentName:"li"},"alter-table")," feature in ast-builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1014"},"#1014"),")"),(0,r.yg)("li",{parentName:"ul"},"Add value/ binary","_","op ",(0,r.yg)("inlineCode",{parentName:"li"},"Parital{Ord,Cmp}")," impl macro ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1013"},"#1013"),")"),(0,r.yg)("li",{parentName:"ul"},"Change to use internal chrono errors in parsing datetime ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1010"},"#1010"),")"),(0,r.yg)("li",{parentName:"ul"},"Resolve unreachable branch of ",(0,r.yg)("inlineCode",{parentName:"li"},"Value::position")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1012"},"#1012"),")"),(0,r.yg)("li",{parentName:"ul"},"Apply binary","_","op macros to existing data types ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ChobobDev"},"@ChobobDev")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/987"},"#987"),")"),(0,r.yg)("li",{parentName:"ul"},"chore: Use rust-cache action to cache dependencies ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/jongwooo"},"@jongwooo")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1006"},"#1006"),")"),(0,r.yg)("li",{parentName:"ul"},"Group the import statements ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/yugeeklab"},"@yugeeklab")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1005"},"#1005"),")"),(0,r.yg)("li",{parentName:"ul"},"Make Tester::new async ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ShaddyDC"},"@ShaddyDC")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1004"},"#1004"),")"),(0,r.yg)("li",{parentName:"ul"},"Make MemoryStorage Store trait features optional, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1003"},"#1003"),")"),(0,r.yg)("li",{parentName:"ul"},"Replace ",(0,r.yg)("inlineCode",{parentName:"li"},"double quotes")," to ",(0,r.yg)("inlineCode",{parentName:"li"},"identifier")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1001"},"#1001"),")"),(0,r.yg)("li",{parentName:"ul"},"Change chrono ",(0,r.yg)("inlineCode",{parentName:"li"},"from_*")," methods to ",(0,r.yg)("inlineCode",{parentName:"li"},"from_*_opt")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1000"},"#1000"),")"),(0,r.yg)("li",{parentName:"ul"},"Improve duplicate column names validation ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/995"},"#995"),")"),(0,r.yg)("li",{parentName:"ul"},"Register ",(0,r.yg)("inlineCode",{parentName:"li"},"lock")," when ",(0,r.yg)("inlineCode",{parentName:"li"},"fetch_all_schemas")," face ",(0,r.yg)("inlineCode",{parentName:"li"},"idle")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/996"},"#996"),")"),(0,r.yg)("li",{parentName:"ul"},"Merge ColumnOption::{Null, NotNull} into a single option ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/986"},"#986"),")"),(0,r.yg)("li",{parentName:"ul"},"Update rust.yml github action to test examples/ ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/994"},"#994"),")")),(0,r.yg)("h2",{id:"-documentation"},"\ud83c\udf33 Documentation"),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},"We now provide an official documentation website at ",(0,r.yg)("a",{parentName:"strong",href:"https://gluesql.org/docs"},"https://gluesql.org/docs"))),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Add documentation for CLI ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1183"},"#1183"),")"),(0,r.yg)("li",{parentName:"ul"},"Add ast","_","builder null handling doc ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/LEE026"},"@LEE026")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1209"},"#1209"),")"),(0,r.yg)("li",{parentName:"ul"},"Add document of datetime current date and time for ast-builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/heewoneha"},"@heewoneha")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1208"},"#1208"),")"),(0,r.yg)("li",{parentName:"ul"},"docs: write position and indexing docs ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/Bangseungjae"},"@Bangseungjae")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1206"},"#1206"),")"),(0,r.yg)("li",{parentName:"ul"},"Add docs/formatting for ast","_","builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/sooyeonyim-t"},"@sooyeonyim-t")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1200"},"#1200"),")"),(0,r.yg)("li",{parentName:"ul"},"Update math basic arithmetic docs for ast","_","builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/changi1122"},"@changi1122")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1202"},"#1202"),")"),(0,r.yg)("li",{parentName:"ul"},"Add pattern-matching doc for ast","_","builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/LEE026"},"@LEE026")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1199"},"#1199"),")"),(0,r.yg)("li",{parentName:"ul"},"Add ast builder Trimming function docs ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/Bangseungjae"},"@Bangseungjae")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1197"},"#1197"),")"),(0,r.yg)("li",{parentName:"ul"},"Add doc about the function Date \\& Time Conversion ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/heewoneha"},"@heewoneha")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1196"},"#1196"),")"),(0,r.yg)("li",{parentName:"ul"},"add Docs/case conversion(upper, lower, InitCap) in ast builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/sooyeonyim-t"},"@sooyeonyim-t")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1195"},"#1195"),")"),(0,r.yg)("li",{parentName:"ul"},"Add math conversion docs for ast","_","builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/changi1122"},"@changi1122")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1192"},"#1192"),")"),(0,r.yg)("li",{parentName:"ul"},"Added documentation for the round, ceil, and floor functions in ast-builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/LEE026"},"@LEE026")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1191"},"#1191"),")"),(0,r.yg)("li",{parentName:"ul"},"Add documentation layout for AstBuilder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1184"},"#1184"),")"),(0,r.yg)("li",{parentName:"ul"},"Add documentation for Json Storage ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1170"},"#1170"),")"),(0,r.yg)("li",{parentName:"ul"},"Add documentation for math functions ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1173"},"#1173"),")"),(0,r.yg)("li",{parentName:"ul"},"Add doc for datetime, geometry, list \\& map and other functions, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1172"},"#1172"),")"),(0,r.yg)("li",{parentName:"ul"},"Add documentation for text functions in SQL ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1167"},"#1167"),")"),(0,r.yg)("li",{parentName:"ul"},"Write docs/ Supported Storages section contents, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1165"},"#1165"),")"),(0,r.yg)("li",{parentName:"ul"},"Add SQL function list with categories to docs/ ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1166"},"#1166"),")"),(0,r.yg)("li",{parentName:"ul"},"Write docs/getting-started/javascript-web.md ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1159"},"#1159"),")"),(0,r.yg)("li",{parentName:"ul"},"Write docs/ Developing Custom Storages contents ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1155"},"#1155"),")"),(0,r.yg)("li",{parentName:"ul"},"docs: add newly added data type into README.md ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ChobobDev"},"@ChobobDev")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1137"},"#1137"),")"),(0,r.yg)("li",{parentName:"ul"},"docs(readme): add discord icon to chat badge ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/LeoDog896"},"@LeoDog896")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1122"},"#1122"),")"),(0,r.yg)("li",{parentName:"ul"},"docs(javascript): update examples link ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/LeoDog896"},"@LeoDog896")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1108"},"#1108"),")")),(0,r.yg)("h3",{id:"docs---setup"},"Docs - setup"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Add gh-action for docs build - runs on both push \\& pr ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1215"},"#1215"),")"),(0,r.yg)("li",{parentName:"ul"},"Setup blog based on docusaurus, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1212"},"#1212"),")"),(0,r.yg)("li",{parentName:"ul"},"Remove mdbook which is replaced by docs/ (docusaurus based) ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1164"},"#1164"),")"),(0,r.yg)("li",{parentName:"ul"},"Add docusaurus deployment github action setup ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1163"},"#1163"),")"),(0,r.yg)("li",{parentName:"ul"},"Update coverage, javascript and rust gh action to ignore ",(0,r.yg)("inlineCode",{parentName:"li"},"docs/**")," pa\u2026 ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1168"},"#1168"),")"),(0,r.yg)("li",{parentName:"ul"},"Update docs/ global styles, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1156"},"#1156"),")"),(0,r.yg)("li",{parentName:"ul"},"Setup new documentation based on docusaurus ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1136"},"#1136"),")")),(0,r.yg)("h2",{id:"-tests"},"\ud83d\udccb Tests"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Add ifnull test suite for ast","_","builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/LEE026"},"@LEE026")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1207"},"#1207"),")"),(0,r.yg)("li",{parentName:"ul"},"Add datetime current date and time test case for ast builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/heewoneha"},"@heewoneha")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1205"},"#1205"),")"),(0,r.yg)("li",{parentName:"ul"},"Add Position and Indexing test code ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/Bangseungjae"},"@Bangseungjae")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1203"},"#1203"),")"),(0,r.yg)("li",{parentName:"ul"},"Add math basic arithmetic test case for ast","_","builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/changi1122"},"@changi1122")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1201"},"#1201"),")"),(0,r.yg)("li",{parentName:"ul"},"Add testcase/formatting for ast","_","builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/sooyeonyim-t"},"@sooyeonyim-t")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1198"},"#1198"),")"),(0,r.yg)("li",{parentName:"ul"},"Add pattern","_","matching test cases for ast","_","builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/LEE026"},"@LEE026")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1194"},"#1194"),")"),(0,r.yg)("li",{parentName:"ul"},"Add test code function / text / trimming ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/Bangseungjae"},"@Bangseungjae")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1190"},"#1190"),")"),(0,r.yg)("li",{parentName:"ul"},"Add Testcase/case conversion ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/sooyeonyim-t"},"@sooyeonyim-t")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1193"},"#1193"),")"),(0,r.yg)("li",{parentName:"ul"},"Add datetime conversion test cases for ast","_","builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/heewoneha"},"@heewoneha")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1187"},"#1187"),")"),(0,r.yg)("li",{parentName:"ul"},"Add math conversion test case for ast","_","builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/changi1122"},"@changi1122")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1189"},"#1189"),")"),(0,r.yg)("li",{parentName:"ul"},"Add rounding test cases for ast","_","builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/LEE026"},"@LEE026")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1186"},"#1186"),")"),(0,r.yg)("li",{parentName:"ul"},"Update delete and insert tests in test-suite/, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1180"},"#1180"),")"),(0,r.yg)("li",{parentName:"ul"},"Remove gen-","_","transaction","_","dictionary","_","tests! in test-suite, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1179"},"#1179"),")"),(0,r.yg)("li",{parentName:"ul"},"Refactor geometry function tests in test-suite, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1176"},"#1176"),")"),(0,r.yg)("li",{parentName:"ul"},"Refactor SQL function tests in test-suite, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1174"},"#1174"),")"),(0,r.yg)("li",{parentName:"ul"},"fix : fix missing intg test for new data type ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ChobobDev"},"@ChobobDev")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1143"},"#1143"),")"),(0,r.yg)("li",{parentName:"ul"},"Add unit tests for ",(0,r.yg)("inlineCode",{parentName:"li"},"TryFrom<&Value> for Decimal")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ChobobDev"},"@ChobobDev")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1139"},"#1139"),")"),(0,r.yg)("li",{parentName:"ul"},'Add "cli" unittest ',(0,r.yg)("a",{parentName:"li",href:"https://github.com/pythonbrad"},"@pythonbrad")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1094"},"#1094"),")"),(0,r.yg)("li",{parentName:"ul"},"Add ",(0,r.yg)("inlineCode",{parentName:"li"},"core/data")," module unit tests ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/pythonbrad"},"@pythonbrad")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1092"},"#1092"),")")),(0,r.yg)("h2",{id:"-bug-fixes"},"\ud83d\udc1b Bug Fixes"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Fix docusaurus pages/index broken link ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1214"},"#1214"),")"),(0,r.yg)("li",{parentName:"ul"},"Fix docs/ Discord GlueSQL channel invite link address ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1213"},"#1213"),")"),(0,r.yg)("li",{parentName:"ul"},"Fix InvalidJsonString error message replacing payload to fileName ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1185"},"#1185"),")"),(0,r.yg)("li",{parentName:"ul"},"Fix TryFrom ",(0,r.yg)("inlineCode",{parentName:"li"},"Value::Str")," to ",(0,r.yg)("inlineCode",{parentName:"li"},"u128")," not to use ",(0,r.yg)("inlineCode",{parentName:"li"},"parse_uuid")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ChobobDev"},"@ChobobDev")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1134"},"#1134"),")"),(0,r.yg)("li",{parentName:"ul"},"Fix column alias with identifer for ",(0,r.yg)("inlineCode",{parentName:"li"},"TableFactor::Derived")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ding-young"},"@ding-young")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1119"},"#1119"),")"),(0,r.yg)("li",{parentName:"ul"},"Pass data even when ",(0,r.yg)("inlineCode",{parentName:"li"},"deleted_by")," is not present ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1117"},"#1117"),")"),(0,r.yg)("li",{parentName:"ul"},"Fix MemoryStorage \\& WebStorage primary key support ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1115"},"#1115"),")"),(0,r.yg)("li",{parentName:"ul"},"Fix ",(0,r.yg)("inlineCode",{parentName:"li"},"plan::validate")," to handle ",(0,r.yg)("inlineCode",{parentName:"li"},"CTAS")," and ",(0,r.yg)("inlineCode",{parentName:"li"},"ITAS")," adding unit test ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1074"},"#1074"),")"),(0,r.yg)("li",{parentName:"ul"},"Fix test-suite tester functions to show (found, expected) shape ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1028"},"#1028"),")")))}s.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/23f93eeb.c9adc153.js b/docs/0.16.0/assets/js/23f93eeb.c9adc153.js new file mode 100644 index 00000000..f9a191c7 --- /dev/null +++ b/docs/0.16.0/assets/js/23f93eeb.c9adc153.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[5120],{5680:(e,t,a)=>{a.d(t,{xA:()=>o,yg:()=>c});var l=a(6540);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function n(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);t&&(l=l.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,l)}return a}function i(e){for(var t=1;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);for(l=0;l=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var p=l.createContext({}),u=function(e){var t=l.useContext(p),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},o=function(e){var t=u(e.components);return l.createElement(p.Provider,{value:t},e.children)},h="mdxType",s={inlineCode:"code",wrapper:function(e){var t=e.children;return l.createElement(l.Fragment,{},t)}},m=l.forwardRef((function(e,t){var a=e.components,r=e.mdxType,n=e.originalType,p=e.parentName,o=g(e,["components","mdxType","originalType","parentName"]),h=u(a),m=r,c=h["".concat(p,".").concat(m)]||h[m]||s[m]||n;return a?l.createElement(c,i(i({ref:t},o),{},{components:a})):l.createElement(c,i({ref:t},o))}));function c(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var n=a.length,i=new Array(n);i[0]=m;var g={};for(var p in t)hasOwnProperty.call(t,p)&&(g[p]=t[p]);g.originalType=e,g[h]="string"==typeof e?e:r,i[1]=g;for(var u=2;u{a.r(t),a.d(t,{assets:()=>p,contentTitle:()=>i,default:()=>s,frontMatter:()=>n,metadata:()=>g,toc:()=>u});var l=a(8168),r=(a(6540),a(5680));const n={title:"Release v0.14",description:"Release Note - v0.14",slug:"release-v0.14",authors:[{name:"Taehoon Moon",title:"Creator of GlueSQL",url:"https://github.com/panarch",image_url:"https://github.com/panarch.png"}],tags:["v0.14","release-note"]},i=void 0,g={permalink:"/docs/0.16.0/blog/release-v0.14",source:"@site/blog/2023-05-27-release-v0.14.md",title:"Release v0.14",description:"Release Note - v0.14",date:"2023-05-27T00:00:00.000Z",formattedDate:"May 27, 2023",tags:[{label:"v0.14",permalink:"/docs/0.16.0/blog/tags/v-0-14"},{label:"release-note",permalink:"/docs/0.16.0/blog/tags/release-note"}],readingTime:10.24,hasTruncateMarker:!1,authors:[{name:"Taehoon Moon",title:"Creator of GlueSQL",url:"https://github.com/panarch",image_url:"https://github.com/panarch.png",imageURL:"https://github.com/panarch.png"}],frontMatter:{title:"Release v0.14",description:"Release Note - v0.14",slug:"release-v0.14",authors:[{name:"Taehoon Moon",title:"Creator of GlueSQL",url:"https://github.com/panarch",image_url:"https://github.com/panarch.png",imageURL:"https://github.com/panarch.png"}],tags:["v0.14","release-note"]},prevItem:{title:"Breaking the Boundary between SQL and NoSQL Databases",permalink:"/docs/0.16.0/blog/breaking-the-boundary-between-sql-and-nosql"}},p={authorsImageUrls:[void 0]},u=[{value:"\ud83d\ude80 Features",id:"-features",level:2},{value:"\ud83c\udf40 Schemaless data support",id:"-schemaless-data-support",level:3},{value:"\ud83c\udf40 IndexedDB & WebStorage supports in JavaScript package",id:"-indexeddb--webstorage-supports-in-javascript-package",level:3},{value:"\ud83c\udf40 Data Types - UINT32, UINT64, UINT128, POINT and FLOAT32",id:"-data-types---uint32-uint64-uint128-point-and-float32",level:3},{value:"\ud83c\udf40 Functions - APPEND, PREPEND, RAND, FIND_IDX, INITCAP and CALC_DISTANCE",id:"-functions---append-prepend-rand-find_idx-initcap-and-calc_distance",level:3},{value:"\ud83c\udf40 Store traits",id:"-store-traits",level:3},{value:"User-level custom function",id:"user-level-custom-function",level:4},{value:"Metadata",id:"metadata",level:4},{value:"\ud83c\udf40 Storages",id:"-storages",level:3},{value:"JSON Storage",id:"json-storage",level:4},{value:"Composite Storage",id:"composite-storage",level:4},{value:"IndexedDB Storage",id:"indexeddb-storage",level:4},{value:"Web Storage",id:"web-storage",level:4},{value:"\ud83c\udf40 Other new features",id:"-other-new-features",level:3},{value:"\ud83c\udf0a Interface Changes",id:"-interface-changes",level:2},{value:"\ud83c\udf1f Improvements",id:"-improvements",level:2},{value:"\ud83c\udf33 Documentation",id:"-documentation",level:2},{value:"Docs - setup",id:"docs---setup",level:3},{value:"\ud83d\udccb Tests",id:"-tests",level:2},{value:"\ud83d\udc1b Bug Fixes",id:"-bug-fixes",level:2}],o={toc:u},h="wrapper";function s(e){let{components:t,...a}=e;return(0,r.yg)(h,(0,l.A)({},o,a,{components:t,mdxType:"MDXLayout"}),(0,r.yg)("p",null,"We now provide an official documentation website at ",(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"https://gluesql.org/docs"},"https://gluesql.org/docs"))),(0,r.yg)("h2",{id:"-features"},"\ud83d\ude80 Features"),(0,r.yg)("h3",{id:"-schemaless-data-support"},"\ud83c\udf40 Schemaless data support"),(0,r.yg)("p",null,"GlueSQL now supports creating tables without a schema, allowing for both structured and unstructured data to be stored in the same table.\nTo create a schemaless table, simply run CREATE TABLE without specifying any columns. For more information on querying schemaless data, please refer to the following link: ",(0,r.yg)("strong",{parentName:"p"},(0,r.yg)("a",{parentName:"strong",href:"https://gluesql.org/docs/dev/sql-syntax/statements/querying/schemaless"},"querying schemaless data"))),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE Bar;\n")),(0,r.yg)("p",null,"To insert values,"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},'INSERT INTO Bar VALUES\n (\'{ "name": "ast", "value": 30 }\'),\n (\'{ "name": "glue", "rate": 3.0, "list": [1, 2, 3] }\'),\n')),(0,r.yg)("p",null,"Then, selecting values from schemaless table is simple."),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT name, rate, list[0] FROM Bar WHERE name = 'glue';\n")),(0,r.yg)("p",null,"e.g."),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},'CREATE TABLE Names (id INTEGER, name TEXT);\nINSERT INTO Names VALUES (1, \'glue\'), (2, \'sql\');\n\nCREATE TABLE Logs;\nINSERT INTO Logs VALUES\n (\'{ "id": 1, "value": 30 }\'),\n (\'{ "id": 2, "rate": 3.0, "list": [1, 2, 3] }\'),\n (\'{ "id": 3, "rate": 5.0, "value": 100 }\');\n\nSELECT * FROM Names JOIN Logs ON Names.id = Logs.id;\n/*\n| id | list | name | rate | value |\n|----|---------|------|------|-------|\n| 1 | | glue | | 30 |\n| 2 |[1, 2, 3]| sql | 3 | |\n*/\n')),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Schemaless data support ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1046"},"#1046"),")")),(0,r.yg)("h3",{id:"-indexeddb--webstorage-supports-in-javascript-package"},"\ud83c\udf40 IndexedDB & WebStorage supports in JavaScript package"),(0,r.yg)("p",null,"GlueSQL supports handling in-memory, localStorage, sessionStorage, and even IndexedDB using the same SQL syntax. All you need to know is how to specify the ",(0,r.yg)("inlineCode",{parentName:"p"},"ENGINE")," when creating a table."),(0,r.yg)("p",null,"e.g."),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE Mem (mid INTEGER) ENGINE = memory;\nCREATE TABLE Loc (lid INTEGER) ENGINE = localStorage;\nCREATE TABLE Ses (sid INTEGER) ENGINE = sessionStorage;\nCREATE TABLE Idb (iid INTEGER) ENGINE = indexedDB;\n\nSELECT\n mid, lid, sid, iid \nFROM Mem\nJOIN Loc\nJOIN Ses\nJOIN Idb;\n")),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Apply CompositeStorage to JS package ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1084"},"#1084"),")")),(0,r.yg)("h3",{id:"-data-types---uint32-uint64-uint128-point-and-float32"},"\ud83c\udf40 Data Types - ",(0,r.yg)("inlineCode",{parentName:"h3"},"UINT32"),", ",(0,r.yg)("inlineCode",{parentName:"h3"},"UINT64"),", ",(0,r.yg)("inlineCode",{parentName:"h3"},"UINT128"),", ",(0,r.yg)("inlineCode",{parentName:"h3"},"POINT")," and ",(0,r.yg)("inlineCode",{parentName:"h3"},"FLOAT32")),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"implement f32 data type ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/pythonbrad"},"@pythonbrad")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1145"},"#1145"),")"),(0,r.yg)("li",{parentName:"ul"},"Implement geometric ",(0,r.yg)("inlineCode",{parentName:"li"},"POINT")," Type and geometric functions ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/seonghun-dev"},"@seonghun-dev")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1048"},"#1048"),")"),(0,r.yg)("li",{parentName:"ul"},"Add ",(0,r.yg)("inlineCode",{parentName:"li"},"UINT32"),", ",(0,r.yg)("inlineCode",{parentName:"li"},"UINT64")," and ",(0,r.yg)("inlineCode",{parentName:"li"},"UINT128")," data types ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ChobobDev"},"@ChobobDev")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1019"},"#1019"),")"),(0,r.yg)("li",{parentName:"ul"},"Add inet datatype ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/pythonbrad"},"@pythonbrad")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1080"},"#1080"),")")),(0,r.yg)("h3",{id:"-functions---append-prepend-rand-find_idx-initcap-and-calc_distance"},"\ud83c\udf40 Functions - ",(0,r.yg)("inlineCode",{parentName:"h3"},"APPEND"),", ",(0,r.yg)("inlineCode",{parentName:"h3"},"PREPEND"),", ",(0,r.yg)("inlineCode",{parentName:"h3"},"RAND"),", ",(0,r.yg)("inlineCode",{parentName:"h3"},"FIND_IDX"),", ",(0,r.yg)("inlineCode",{parentName:"h3"},"INITCAP")," and ",(0,r.yg)("inlineCode",{parentName:"h3"},"CALC_DISTANCE")),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Feat : add calc","_","distance function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/seonghun-dev"},"@seonghun-dev")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1153"},"#1153"),")"),(0,r.yg)("li",{parentName:"ul"},"Add ",(0,r.yg)("inlineCode",{parentName:"li"},"PREPEND")," function for ",(0,r.yg)("inlineCode",{parentName:"li"},"LIST")," data type ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/seonghun-dev"},"@seonghun-dev")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1149"},"#1149"),")"),(0,r.yg)("li",{parentName:"ul"},"add initcap function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/pythonbrad"},"@pythonbrad")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1064"},"#1064"),")"),(0,r.yg)("li",{parentName:"ul"},"Implement ",(0,r.yg)("inlineCode",{parentName:"li"},"FIND_IDX")," function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/zmrdltl"},"@zmrdltl")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1100"},"#1100"),")"),(0,r.yg)("li",{parentName:"ul"},"Implement Rand function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/pythonbrad"},"@pythonbrad")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1063"},"#1063"),")"),(0,r.yg)("li",{parentName:"ul"},"Add Append Function to LIST DataType ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/seonghun-dev"},"@seonghun-dev")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1047"},"#1047"),")")),(0,r.yg)("h3",{id:"-store-traits"},"\ud83c\udf40 Store traits"),(0,r.yg)("h4",{id:"user-level-custom-function"},"User-level custom function"),(0,r.yg)("p",null,"By implementing both the CustomFunction and CustomFunctionMut traits, users can create, use, and delete user-level custom functions. Although GlueSQL plans to continuously add various functions, users may still find them insufficient. In such cases, users can create their own user-level custom functions to supplement the built-in functions. Additionally, if there are repetitive business logic codes, they can be stored as custom functions.\ne.g."),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE FUNCTION ADD_ONE (n INT, x INT DEFAULT 1) RETURN n + x;\n\nSELECT ADD_ONE(10) AS test;\n\nDROP FUNCTION ADD_ONE;\n")),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Support user level sql function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/pythonbrad"},"@pythonbrad")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1095"},"#1095"),")")),(0,r.yg)("h4",{id:"metadata"},"Metadata"),(0,r.yg)("p",null,"The Metadata trait is an optional implementation for providing additional metadata support in GlueSQL. GlueSQL does not enforce any specific metadata implementation, allowing custom storage developers to decide which type of metadata, such as create time, modify time, etc., they want to provide."),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Support Metadata trait ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1096"},"#1096"),")")),(0,r.yg)("h3",{id:"-storages"},"\ud83c\udf40 Storages"),(0,r.yg)("h4",{id:"json-storage"},"JSON Storage"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Add JsonStorage support to CLI ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1135"},"#1135"),")"),(0,r.yg)("li",{parentName:"ul"},"Rename ",(0,r.yg)("inlineCode",{parentName:"li"},"Jsonl"),"Storage to ",(0,r.yg)("inlineCode",{parentName:"li"},"Json"),"Storage ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1128"},"#1128"),")"),(0,r.yg)("li",{parentName:"ul"},"Support ",(0,r.yg)("inlineCode",{parentName:"li"},"JSON")," format in ",(0,r.yg)("inlineCode",{parentName:"li"},"JSONL storage")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1123"},"#1123"),")"),(0,r.yg)("li",{parentName:"ul"},"Support ",(0,r.yg)("inlineCode",{parentName:"li"},"Jsonl")," Storage ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1053"},"#1053"),")")),(0,r.yg)("h4",{id:"composite-storage"},"Composite Storage"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Add CompositeStorage which bundles multiple storages ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1068"},"#1068"),")")),(0,r.yg)("h4",{id:"indexeddb-storage"},"IndexedDB Storage"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Add IndexedDB storage support ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1067"},"#1067"),")")),(0,r.yg)("h4",{id:"web-storage"},"Web Storage"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Add WebStorage - support localStorage \\& sessionStorage for web browsers ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1050"},"#1050"),")")),(0,r.yg)("h3",{id:"-other-new-features"},"\ud83c\udf40 Other new features"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Wrap identifiers with double quote (",(0,r.yg)("inlineCode",{parentName:"li"},'"'),") at ",(0,r.yg)("inlineCode",{parentName:"li"},"to_sql")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1130"},"#1130"),")"),(0,r.yg)("li",{parentName:"ul"},"Support Values Query at ASTBuilder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1041"},"#1041"),")"),(0,r.yg)("li",{parentName:"ul"},"Support ",(0,r.yg)("inlineCode",{parentName:"li"},"Schema::from_ddl(ddl: &str) -> String")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1089"},"#1089"),")"),(0,r.yg)("li",{parentName:"ul"},"Support column alias for Table, Derived Table ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ding-young"},"@ding-young")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1065"},"#1065"),")"),(0,r.yg)("li",{parentName:"ul"},"Support ",(0,r.yg)("inlineCode",{parentName:"li"},"TableFactor::{Derived, Dictionary, Series}")," in AstBuilder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1007"},"#1007"),")")),(0,r.yg)("h2",{id:"-interface-changes"},"\ud83c\udf0a Interface Changes"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Remove Store trait related cfg features, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1091"},"#1091"),")"),(0,r.yg)("li",{parentName:"ul"},"Refactor CreateTable.columns from ",(0,r.yg)("inlineCode",{parentName:"li"},"Vec")," to ",(0,r.yg)("inlineCode",{parentName:"li"},"Option>")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1086"},"#1086"),")"),(0,r.yg)("li",{parentName:"ul"},"Remove ",(0,r.yg)("inlineCode",{parentName:"li"},"MutResult")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1073"},"#1073"),")"),(0,r.yg)("li",{parentName:"ul"},"Update all store mut trait methods to take \\&mut self ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1072"},"#1072"),")"),(0,r.yg)("li",{parentName:"ul"},"Change StoreMut interface to use \\&mut self, not to take ownership ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1071"},"#1071"),")"),(0,r.yg)("li",{parentName:"ul"},"Modify default ColumnOption from NOT NULL to NULL ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/997"},"#997"),")")),(0,r.yg)("h2",{id:"-improvements"},"\ud83c\udf1f Improvements"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Add a case for insert with source ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1211"},"#1211"),")"),(0,r.yg)("li",{parentName:"ul"},"Apply workspace inheritance to remaining Cargo.toml in storages/, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1181"},"#1181"),")"),(0,r.yg)("li",{parentName:"ul"},"Add nullable, key, default to ",(0,r.yg)("inlineCode",{parentName:"li"},"GLUE_TABLE_COLUMNS")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1177"},"#1177"),")"),(0,r.yg)("li",{parentName:"ul"},"Update core to bundle all errors using error module, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1178"},"#1178"),")"),(0,r.yg)("li",{parentName:"ul"},"Update global Error enum to display with error module prefix ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1175"},"#1175"),")"),(0,r.yg)("li",{parentName:"ul"},"fix: typo ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1161"},"#1161"),")"),(0,r.yg)("li",{parentName:"ul"},"Move the SCHEMA","_","PREFIX const into an impl in SledStorage ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/garypen"},"@garypen")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1151"},"#1151"),")"),(0,r.yg)("li",{parentName:"ul"},"Merge evaluate","_","stateless into evaluate, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1132"},"#1132"),")"),(0,r.yg)("li",{parentName:"ul"},"Remove memory-storage dep from JsonStorage/ Cargo.toml ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1131"},"#1131"),")"),(0,r.yg)("li",{parentName:"ul"},"Simplify JsonlStorage codes ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1126"},"#1126"),")"),(0,r.yg)("li",{parentName:"ul"},"Bump rust version to 1.68 ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1125"},"#1125"),")"),(0,r.yg)("li",{parentName:"ul"},"Keep ",(0,r.yg)("inlineCode",{parentName:"li"},"Cargo.lock")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1121"},"#1121"),")"),(0,r.yg)("li",{parentName:"ul"},"Replace closure to variable in ",(0,r.yg)("inlineCode",{parentName:"li"},"data/interval")," module ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1118"},"#1118"),")"),(0,r.yg)("li",{parentName:"ul"},"Add ",(0,r.yg)("inlineCode",{parentName:"li"},"f64")," support to ",(0,r.yg)("inlineCode",{parentName:"li"},"data::Key")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1114"},"#1114"),")"),(0,r.yg)("li",{parentName:"ul"},"Add Ord impl for Key, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1110"},"#1110"),")"),(0,r.yg)("li",{parentName:"ul"},"join","_","expr when in","_","subquery, exists expr in join constraint ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ding-young"},"@ding-young")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1112"},"#1112"),")"),(0,r.yg)("li",{parentName:"ul"},"Split JS related GitHub action, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1109"},"#1109"),")"),(0,r.yg)("li",{parentName:"ul"},"Fix error handling for ",(0,r.yg)("inlineCode",{parentName:"li"},"ilike")," function on ",(0,r.yg)("inlineCode",{parentName:"li"},"Literal")," being treated as\u2026 ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1107"},"#1107"),")"),(0,r.yg)("li",{parentName:"ul"},"Remove ",(0,r.yg)("inlineCode",{parentName:"li"},"Rc")," in ",(0,r.yg)("inlineCode",{parentName:"li"},"validate.rs")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1106"},"#1106"),")"),(0,r.yg)("li",{parentName:"ul"},"Remove ",(0,r.yg)("inlineCode",{parentName:"li"},"Error::Storage")," variant ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1105"},"#1105"),")"),(0,r.yg)("li",{parentName:"ul"},"Replace ",(0,r.yg)("inlineCode",{parentName:"li"},"Box::pin")," to ",(0,r.yg)("inlineCode",{parentName:"li"},"futures_enum::Stream")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1103"},"#1103"),")"),(0,r.yg)("li",{parentName:"ul"},"Remove stream unneeded map ok uses ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1104"},"#1104"),")"),(0,r.yg)("li",{parentName:"ul"},"Replace ",(0,r.yg)("inlineCode",{parentName:"li"},"TryStream")," to ",(0,r.yg)("inlineCode",{parentName:"li"},"Stream")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1102"},"#1102"),")"),(0,r.yg)("li",{parentName:"ul"},"Remove ",(0,r.yg)("inlineCode",{parentName:"li"},"Rc")," from ",(0,r.yg)("inlineCode",{parentName:"li"},"ColumnValidation")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1101"},"#1101"),")"),(0,r.yg)("li",{parentName:"ul"},"Remove unneeded Rc uses in fetch","_","labels ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1098"},"#1098"),")"),(0,r.yg)("li",{parentName:"ul"},"Simplify TryStreamExt using codes in join executor, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1097"},"#1097"),")"),(0,r.yg)("li",{parentName:"ul"},"Fix typo in plan/validate.rs ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1093"},"#1093"),")"),(0,r.yg)("li",{parentName:"ul"},"Update IdbStorage to use Schema::{to","_","ddl, from","_","ddl} to manage schema \u2026 ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1090"},"#1090"),")"),(0,r.yg)("li",{parentName:"ul"},"Update Cargo.toml files to inherit workspace level configs, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1088"},"#1088"),")"),(0,r.yg)("li",{parentName:"ul"},"Add Error enum to core::prelude ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1087"},"#1087"),")"),(0,r.yg)("li",{parentName:"ul"},"Update ",(0,r.yg)("inlineCode",{parentName:"li"},"StringExt")," implementation to use ",(0,r.yg)("inlineCode",{parentName:"li"},"str")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1082"},"#1082"),")"),(0,r.yg)("li",{parentName:"ul"},"Add enum ",(0,r.yg)("inlineCode",{parentName:"li"},"StrSlice")," under enum ",(0,r.yg)("inlineCode",{parentName:"li"},"Evaluated")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/zmrdltl"},"@zmrdltl")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/999"},"#999"),")"),(0,r.yg)("li",{parentName:"ul"},"refactor plan::validate::Context.labels from String to str ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1079"},"#1079"),")"),(0,r.yg)("li",{parentName:"ul"},"Replace ",(0,r.yg)("inlineCode",{parentName:"li"},"dyn object")," to generic ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1075"},"#1075"),")"),(0,r.yg)("li",{parentName:"ul"},"Implement ValidationContext(schema","_","map + alias) to enhance validation of ambiguous columns ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/883"},"#883"),")"),(0,r.yg)("li",{parentName:"ul"},"Remove ",(0,r.yg)("inlineCode",{parentName:"li"},"clone")," in ",(0,r.yg)("inlineCode",{parentName:"li"},"check_table_factor")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1058"},"#1058"),")"),(0,r.yg)("li",{parentName:"ul"},"Bump rust-toolchain version to ",(0,r.yg)("inlineCode",{parentName:"li"},"1.66")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1057"},"#1057"),")"),(0,r.yg)("li",{parentName:"ul"},"Bump ",(0,r.yg)("inlineCode",{parentName:"li"},"sqlparser")," version to ",(0,r.yg)("inlineCode",{parentName:"li"},"0.30")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1056"},"#1056"),")"),(0,r.yg)("li",{parentName:"ul"},"Replace ",(0,r.yg)("inlineCode",{parentName:"li"},"Box::pin")," to ",(0,r.yg)("inlineCode",{parentName:"li"},"futures_enum")," in aggregate module ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1055"},"#1055"),")"),(0,r.yg)("li",{parentName:"ul"},"Update js/ Cargo.toml to use gloo-utils for serde handling ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1049"},"#1049"),")"),(0,r.yg)("li",{parentName:"ul"},"Remove ast::ColumnOption and merge UNIQUE option to ColumnDef ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1044"},"#1044"),")"),(0,r.yg)("li",{parentName:"ul"},"Rewrite \\& simplify plan/context.rs codes, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1045"},"#1045"),")"),(0,r.yg)("li",{parentName:"ul"},"Move ast::ColumnOption::Default variant to ColumnDef ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1042"},"#1042"),")"),(0,r.yg)("li",{parentName:"ul"},"[AST-Builder]"," Remove unused prebuild nodes ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ding-young"},"@ding-young")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1043"},"#1043"),")"),(0,r.yg)("li",{parentName:"ul"},"Remove data::RowError, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1040"},"#1040"),")"),(0,r.yg)("li",{parentName:"ul"},"Reorder project in ASTBuilder (project -> ordery","_","by -> limit,offset) ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1039"},"#1039"),")"),(0,r.yg)("li",{parentName:"ul"},"Remove unused LimitOffsetNode in AST builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1038"},"#1038"),")"),(0,r.yg)("li",{parentName:"ul"},"Rename executor/ blend.rs module to project.rs ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/SaumyaBhushan"},"@SaumyaBhushan")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1036"},"#1036"),")"),(0,r.yg)("li",{parentName:"ul"},"Add Debug to AST builder nodes ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1022"},"#1022"),")"),(0,r.yg)("li",{parentName:"ul"},"Bump rust toolchain version to 1.65 ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1035"},"#1035"),")"),(0,r.yg)("li",{parentName:"ul"},"Remove ",(0,r.yg)("inlineCode",{parentName:"li"},"Content::Shared")," variant in executor/ ",(0,r.yg)("inlineCode",{parentName:"li"},"RowContext")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1032"},"#1032"),")"),(0,r.yg)("li",{parentName:"ul"},"Merge insert logics in row.rs \\& execute.rs into executor/insert.rs ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1031"},"#1031"),")"),(0,r.yg)("li",{parentName:"ul"},"Merge FilterContext and BlendContext into RowContext ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1029"},"#1029"),")"),(0,r.yg)("li",{parentName:"ul"},"Update ",(0,r.yg)("inlineCode",{parentName:"li"},"data::Row")," to contain columns ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1026"},"#1026"),")"),(0,r.yg)("li",{parentName:"ul"},"Add LIST type support in CONCAT function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/seonghun-dev"},"@seonghun-dev")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1021"},"#1021"),")"),(0,r.yg)("li",{parentName:"ul"},"Remove LimitOffsetNode in AST builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1023"},"#1023"),")"),(0,r.yg)("li",{parentName:"ul"},"Fix typo ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1020"},"#1020"),")"),(0,r.yg)("li",{parentName:"ul"},"Add NumericNode to handle numeric value inputs in AST builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1017"},"#1017"),")"),(0,r.yg)("li",{parentName:"ul"},"Update ValueError::InvalidJsonString error to show input text ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1018"},"#1018"),")"),(0,r.yg)("li",{parentName:"ul"},"Add null() func which makes NULL value in AST builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1016"},"#1016"),")"),(0,r.yg)("li",{parentName:"ul"},"Add --all-targets option to cargo clippy rust gh-action ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1015"},"#1015"),")"),(0,r.yg)("li",{parentName:"ul"},"Move import ",(0,r.yg)("inlineCode",{parentName:"li"},"ColumnOption")," used only by ",(0,r.yg)("inlineCode",{parentName:"li"},"alter-table")," feature in ast-builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1014"},"#1014"),")"),(0,r.yg)("li",{parentName:"ul"},"Add value/ binary","_","op ",(0,r.yg)("inlineCode",{parentName:"li"},"Parital{Ord,Cmp}")," impl macro ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1013"},"#1013"),")"),(0,r.yg)("li",{parentName:"ul"},"Change to use internal chrono errors in parsing datetime ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1010"},"#1010"),")"),(0,r.yg)("li",{parentName:"ul"},"Resolve unreachable branch of ",(0,r.yg)("inlineCode",{parentName:"li"},"Value::position")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1012"},"#1012"),")"),(0,r.yg)("li",{parentName:"ul"},"Apply binary","_","op macros to existing data types ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ChobobDev"},"@ChobobDev")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/987"},"#987"),")"),(0,r.yg)("li",{parentName:"ul"},"chore: Use rust-cache action to cache dependencies ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/jongwooo"},"@jongwooo")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1006"},"#1006"),")"),(0,r.yg)("li",{parentName:"ul"},"Group the import statements ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/yugeeklab"},"@yugeeklab")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1005"},"#1005"),")"),(0,r.yg)("li",{parentName:"ul"},"Make Tester::new async ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ShaddyDC"},"@ShaddyDC")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1004"},"#1004"),")"),(0,r.yg)("li",{parentName:"ul"},"Make MemoryStorage Store trait features optional, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1003"},"#1003"),")"),(0,r.yg)("li",{parentName:"ul"},"Replace ",(0,r.yg)("inlineCode",{parentName:"li"},"double quotes")," to ",(0,r.yg)("inlineCode",{parentName:"li"},"identifier")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1001"},"#1001"),")"),(0,r.yg)("li",{parentName:"ul"},"Change chrono ",(0,r.yg)("inlineCode",{parentName:"li"},"from_*")," methods to ",(0,r.yg)("inlineCode",{parentName:"li"},"from_*_opt")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1000"},"#1000"),")"),(0,r.yg)("li",{parentName:"ul"},"Improve duplicate column names validation ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/995"},"#995"),")"),(0,r.yg)("li",{parentName:"ul"},"Register ",(0,r.yg)("inlineCode",{parentName:"li"},"lock")," when ",(0,r.yg)("inlineCode",{parentName:"li"},"fetch_all_schemas")," face ",(0,r.yg)("inlineCode",{parentName:"li"},"idle")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/996"},"#996"),")"),(0,r.yg)("li",{parentName:"ul"},"Merge ColumnOption::{Null, NotNull} into a single option ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/986"},"#986"),")"),(0,r.yg)("li",{parentName:"ul"},"Update rust.yml github action to test examples/ ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/994"},"#994"),")")),(0,r.yg)("h2",{id:"-documentation"},"\ud83c\udf33 Documentation"),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},"We now provide an official documentation website at ",(0,r.yg)("a",{parentName:"strong",href:"https://gluesql.org/docs"},"https://gluesql.org/docs"))),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Add documentation for CLI ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1183"},"#1183"),")"),(0,r.yg)("li",{parentName:"ul"},"Add ast","_","builder null handling doc ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/LEE026"},"@LEE026")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1209"},"#1209"),")"),(0,r.yg)("li",{parentName:"ul"},"Add document of datetime current date and time for ast-builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/heewoneha"},"@heewoneha")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1208"},"#1208"),")"),(0,r.yg)("li",{parentName:"ul"},"docs: write position and indexing docs ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/Bangseungjae"},"@Bangseungjae")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1206"},"#1206"),")"),(0,r.yg)("li",{parentName:"ul"},"Add docs/formatting for ast","_","builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/sooyeonyim-t"},"@sooyeonyim-t")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1200"},"#1200"),")"),(0,r.yg)("li",{parentName:"ul"},"Update math basic arithmetic docs for ast","_","builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/changi1122"},"@changi1122")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1202"},"#1202"),")"),(0,r.yg)("li",{parentName:"ul"},"Add pattern-matching doc for ast","_","builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/LEE026"},"@LEE026")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1199"},"#1199"),")"),(0,r.yg)("li",{parentName:"ul"},"Add ast builder Trimming function docs ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/Bangseungjae"},"@Bangseungjae")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1197"},"#1197"),")"),(0,r.yg)("li",{parentName:"ul"},"Add doc about the function Date \\& Time Conversion ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/heewoneha"},"@heewoneha")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1196"},"#1196"),")"),(0,r.yg)("li",{parentName:"ul"},"add Docs/case conversion(upper, lower, InitCap) in ast builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/sooyeonyim-t"},"@sooyeonyim-t")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1195"},"#1195"),")"),(0,r.yg)("li",{parentName:"ul"},"Add math conversion docs for ast","_","builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/changi1122"},"@changi1122")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1192"},"#1192"),")"),(0,r.yg)("li",{parentName:"ul"},"Added documentation for the round, ceil, and floor functions in ast-builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/LEE026"},"@LEE026")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1191"},"#1191"),")"),(0,r.yg)("li",{parentName:"ul"},"Add documentation layout for AstBuilder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1184"},"#1184"),")"),(0,r.yg)("li",{parentName:"ul"},"Add documentation for Json Storage ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1170"},"#1170"),")"),(0,r.yg)("li",{parentName:"ul"},"Add documentation for math functions ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1173"},"#1173"),")"),(0,r.yg)("li",{parentName:"ul"},"Add doc for datetime, geometry, list \\& map and other functions, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1172"},"#1172"),")"),(0,r.yg)("li",{parentName:"ul"},"Add documentation for text functions in SQL ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1167"},"#1167"),")"),(0,r.yg)("li",{parentName:"ul"},"Write docs/ Supported Storages section contents, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1165"},"#1165"),")"),(0,r.yg)("li",{parentName:"ul"},"Add SQL function list with categories to docs/ ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1166"},"#1166"),")"),(0,r.yg)("li",{parentName:"ul"},"Write docs/getting-started/javascript-web.md ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1159"},"#1159"),")"),(0,r.yg)("li",{parentName:"ul"},"Write docs/ Developing Custom Storages contents ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1155"},"#1155"),")"),(0,r.yg)("li",{parentName:"ul"},"docs: add newly added data type into README.md ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ChobobDev"},"@ChobobDev")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1137"},"#1137"),")"),(0,r.yg)("li",{parentName:"ul"},"docs(readme): add discord icon to chat badge ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/LeoDog896"},"@LeoDog896")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1122"},"#1122"),")"),(0,r.yg)("li",{parentName:"ul"},"docs(javascript): update examples link ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/LeoDog896"},"@LeoDog896")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1108"},"#1108"),")")),(0,r.yg)("h3",{id:"docs---setup"},"Docs - setup"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Add gh-action for docs build - runs on both push \\& pr ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1215"},"#1215"),")"),(0,r.yg)("li",{parentName:"ul"},"Setup blog based on docusaurus, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1212"},"#1212"),")"),(0,r.yg)("li",{parentName:"ul"},"Remove mdbook which is replaced by docs/ (docusaurus based) ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1164"},"#1164"),")"),(0,r.yg)("li",{parentName:"ul"},"Add docusaurus deployment github action setup ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1163"},"#1163"),")"),(0,r.yg)("li",{parentName:"ul"},"Update coverage, javascript and rust gh action to ignore ",(0,r.yg)("inlineCode",{parentName:"li"},"docs/**")," pa\u2026 ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1168"},"#1168"),")"),(0,r.yg)("li",{parentName:"ul"},"Update docs/ global styles, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1156"},"#1156"),")"),(0,r.yg)("li",{parentName:"ul"},"Setup new documentation based on docusaurus ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1136"},"#1136"),")")),(0,r.yg)("h2",{id:"-tests"},"\ud83d\udccb Tests"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Add ifnull test suite for ast","_","builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/LEE026"},"@LEE026")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1207"},"#1207"),")"),(0,r.yg)("li",{parentName:"ul"},"Add datetime current date and time test case for ast builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/heewoneha"},"@heewoneha")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1205"},"#1205"),")"),(0,r.yg)("li",{parentName:"ul"},"Add Position and Indexing test code ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/Bangseungjae"},"@Bangseungjae")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1203"},"#1203"),")"),(0,r.yg)("li",{parentName:"ul"},"Add math basic arithmetic test case for ast","_","builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/changi1122"},"@changi1122")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1201"},"#1201"),")"),(0,r.yg)("li",{parentName:"ul"},"Add testcase/formatting for ast","_","builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/sooyeonyim-t"},"@sooyeonyim-t")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1198"},"#1198"),")"),(0,r.yg)("li",{parentName:"ul"},"Add pattern","_","matching test cases for ast","_","builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/LEE026"},"@LEE026")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1194"},"#1194"),")"),(0,r.yg)("li",{parentName:"ul"},"Add test code function / text / trimming ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/Bangseungjae"},"@Bangseungjae")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1190"},"#1190"),")"),(0,r.yg)("li",{parentName:"ul"},"Add Testcase/case conversion ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/sooyeonyim-t"},"@sooyeonyim-t")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1193"},"#1193"),")"),(0,r.yg)("li",{parentName:"ul"},"Add datetime conversion test cases for ast","_","builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/heewoneha"},"@heewoneha")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1187"},"#1187"),")"),(0,r.yg)("li",{parentName:"ul"},"Add math conversion test case for ast","_","builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/changi1122"},"@changi1122")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1189"},"#1189"),")"),(0,r.yg)("li",{parentName:"ul"},"Add rounding test cases for ast","_","builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/LEE026"},"@LEE026")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1186"},"#1186"),")"),(0,r.yg)("li",{parentName:"ul"},"Update delete and insert tests in test-suite/, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1180"},"#1180"),")"),(0,r.yg)("li",{parentName:"ul"},"Remove gen-","_","transaction","_","dictionary","_","tests! in test-suite, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1179"},"#1179"),")"),(0,r.yg)("li",{parentName:"ul"},"Refactor geometry function tests in test-suite, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1176"},"#1176"),")"),(0,r.yg)("li",{parentName:"ul"},"Refactor SQL function tests in test-suite, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1174"},"#1174"),")"),(0,r.yg)("li",{parentName:"ul"},"fix : fix missing intg test for new data type ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ChobobDev"},"@ChobobDev")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1143"},"#1143"),")"),(0,r.yg)("li",{parentName:"ul"},"Add unit tests for ",(0,r.yg)("inlineCode",{parentName:"li"},"TryFrom<&Value> for Decimal")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ChobobDev"},"@ChobobDev")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1139"},"#1139"),")"),(0,r.yg)("li",{parentName:"ul"},'Add "cli" unittest ',(0,r.yg)("a",{parentName:"li",href:"https://github.com/pythonbrad"},"@pythonbrad")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1094"},"#1094"),")"),(0,r.yg)("li",{parentName:"ul"},"Add ",(0,r.yg)("inlineCode",{parentName:"li"},"core/data")," module unit tests ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/pythonbrad"},"@pythonbrad")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1092"},"#1092"),")")),(0,r.yg)("h2",{id:"-bug-fixes"},"\ud83d\udc1b Bug Fixes"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Fix docusaurus pages/index broken link ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1214"},"#1214"),")"),(0,r.yg)("li",{parentName:"ul"},"Fix docs/ Discord GlueSQL channel invite link address ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1213"},"#1213"),")"),(0,r.yg)("li",{parentName:"ul"},"Fix InvalidJsonString error message replacing payload to fileName ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1185"},"#1185"),")"),(0,r.yg)("li",{parentName:"ul"},"Fix TryFrom ",(0,r.yg)("inlineCode",{parentName:"li"},"Value::Str")," to ",(0,r.yg)("inlineCode",{parentName:"li"},"u128")," not to use ",(0,r.yg)("inlineCode",{parentName:"li"},"parse_uuid")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ChobobDev"},"@ChobobDev")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1134"},"#1134"),")"),(0,r.yg)("li",{parentName:"ul"},"Fix column alias with identifer for ",(0,r.yg)("inlineCode",{parentName:"li"},"TableFactor::Derived")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ding-young"},"@ding-young")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1119"},"#1119"),")"),(0,r.yg)("li",{parentName:"ul"},"Pass data even when ",(0,r.yg)("inlineCode",{parentName:"li"},"deleted_by")," is not present ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1117"},"#1117"),")"),(0,r.yg)("li",{parentName:"ul"},"Fix MemoryStorage \\& WebStorage primary key support ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1115"},"#1115"),")"),(0,r.yg)("li",{parentName:"ul"},"Fix ",(0,r.yg)("inlineCode",{parentName:"li"},"plan::validate")," to handle ",(0,r.yg)("inlineCode",{parentName:"li"},"CTAS")," and ",(0,r.yg)("inlineCode",{parentName:"li"},"ITAS")," adding unit test ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1074"},"#1074"),")"),(0,r.yg)("li",{parentName:"ul"},"Fix test-suite tester functions to show (found, expected) shape ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1028"},"#1028"),")")))}s.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/25196878.ca24ae51.js b/docs/0.16.0/assets/js/25196878.ca24ae51.js new file mode 100644 index 00000000..22581eb3 --- /dev/null +++ b/docs/0.16.0/assets/js/25196878.ca24ae51.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[2997],{5680:(e,t,n)=>{n.d(t,{xA:()=>c,yg:()=>p});var a=n(6540);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function s(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var l=a.createContext({}),u=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},c=function(e){var t=u(e.components);return a.createElement(l.Provider,{value:t},e.children)},d="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,l=e.parentName,c=r(e,["components","mdxType","originalType","parentName"]),d=u(n),m=o,p=d["".concat(l,".").concat(m)]||d[m]||h[m]||i;return n?a.createElement(p,s(s({ref:t},c),{},{components:n})):a.createElement(p,s({ref:t},c))}));function p(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,s=new Array(i);s[0]=m;var r={};for(var l in t)hasOwnProperty.call(t,l)&&(r[l]=t[l]);r.originalType=e,r[d]="string"==typeof e?e:o,s[1]=r;for(var u=2;u{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>s,default:()=>h,frontMatter:()=>i,metadata:()=>r,toc:()=>u});var a=n(8168),o=(n(6540),n(5680));const i={title:"Test-Driven Documentation - Automating User Manual Creation in GlueSQL",description:"Test-Driven Documentation - Automating User Manual Creation in GlueSQL",slug:"test-driven-documentation",authors:[{name:"Taehoon Moon",title:"Creator of GlueSQL",url:"https://github.com/panarch",image_url:"https://github.com/panarch.png"}],tags:["ChatGPT","Test-Driven-Documentation","TDD","Database","Documentation","Automation"]},s="Test-Driven Documentation - Automating User Manual Creation in GlueSQL",r={permalink:"/docs/0.16.0/blog/test-driven-documentation",source:"@site/blog/2023-05-30-test-driven-documentation.md",title:"Test-Driven Documentation - Automating User Manual Creation in GlueSQL",description:"Test-Driven Documentation - Automating User Manual Creation in GlueSQL",date:"2023-05-30T00:00:00.000Z",formattedDate:"May 30, 2023",tags:[{label:"ChatGPT",permalink:"/docs/0.16.0/blog/tags/chat-gpt"},{label:"Test-Driven-Documentation",permalink:"/docs/0.16.0/blog/tags/test-driven-documentation"},{label:"TDD",permalink:"/docs/0.16.0/blog/tags/tdd"},{label:"Database",permalink:"/docs/0.16.0/blog/tags/database"},{label:"Documentation",permalink:"/docs/0.16.0/blog/tags/documentation"},{label:"Automation",permalink:"/docs/0.16.0/blog/tags/automation"}],readingTime:9.265,hasTruncateMarker:!1,authors:[{name:"Taehoon Moon",title:"Creator of GlueSQL",url:"https://github.com/panarch",image_url:"https://github.com/panarch.png",imageURL:"https://github.com/panarch.png"}],frontMatter:{title:"Test-Driven Documentation - Automating User Manual Creation in GlueSQL",description:"Test-Driven Documentation - Automating User Manual Creation in GlueSQL",slug:"test-driven-documentation",authors:[{name:"Taehoon Moon",title:"Creator of GlueSQL",url:"https://github.com/panarch",image_url:"https://github.com/panarch.png",imageURL:"https://github.com/panarch.png"}],tags:["ChatGPT","Test-Driven-Documentation","TDD","Database","Documentation","Automation"]},prevItem:{title:"GlueSQL - Revolutionizing Databases by Unifying Query Interfaces",permalink:"/docs/0.16.0/blog/revolutionizing-databases-by-unifying-query-interfaces"},nextItem:{title:"Breaking the Boundary between SQL and NoSQL Databases",permalink:"/docs/0.16.0/blog/breaking-the-boundary-between-sql-and-nosql"}},l={authorsImageUrls:[void 0]},u=[{value:"Introduction: GlueSQL and Test-Driven Documentation",id:"introduction-gluesql-and-test-driven-documentation",level:2},{value:"Test Codes and Documentation",id:"test-codes-and-documentation",level:2},{value:"Leveraging ChatGPT",id:"leveraging-chatgpt",level:2},{value:"Success Case: Automated User Manual of GlueSQL",id:"success-case-automated-user-manual-of-gluesql",level:2},{value:"Future Plans: Fully Automating Documentation Generation",id:"future-plans-fully-automating-documentation-generation",level:2},{value:"Conclusion: The Value of Test-Driven Documentation",id:"conclusion-the-value-of-test-driven-documentation",level:2}],c={toc:u},d="wrapper";function h(e){let{components:t,...i}=e;return(0,o.yg)(d,(0,a.A)({},c,i,{components:t,mdxType:"MDXLayout"}),(0,o.yg)("h2",{id:"introduction-gluesql-and-test-driven-documentation"},"Introduction: GlueSQL and Test-Driven Documentation"),(0,o.yg)("p",null,"Recently, the GlueSQL project reached a significant milestone with the release of version 0.14. This new version brings a host of fresh features to the table, yet one of the most notable changes is in the realm of documentation. For the first time, we're proud to announce the launch of our official documentation website. Interested readers can explore the full range of user manuals at ",(0,o.yg)("a",{parentName:"p",href:"https://gluesql.org/docs"},"https://gluesql.org/docs"),"."),(0,o.yg)("p",null,"Prior to this update, the only way to navigate GlueSQL was by manually inspecting the test code within the test suite. With the recent release, however, a comprehensive user manual has been made public to facilitate a more user-friendly experience. We hope that this new addition will prove beneficial to a broad spectrum of users."),(0,o.yg)("p",null,"The task of compiling an entire database manual in one go was daunting due to the sheer volume of content required. Surprisingly, this process turned out to be smoother than initially anticipated, largely due to the invaluable aid of ChatGPT, which was instrumental in automating much of the document creation. Specifically, around 80% of the SQL Syntax section was generated using this tool."),(0,o.yg)("p",null,"This remarkable feat was only possible due to the solid foundation of test codes previously established in GlueSQL. In this article, we'll share how we managed to leverage ChatGPT in such a unique way. Based on our recent experience of crafting documents grounded in testing, we've begun to consider the possibility of entirely automating document creation, save for the initial stages."),(0,o.yg)("p",null,"Along with sharing our journey so far, we will also reveal our plans for future test-based automation of documentation within GlueSQL."),(0,o.yg)("h2",{id:"test-codes-and-documentation"},"Test Codes and Documentation"),(0,o.yg)("p",null,"The GlueSQL project has placed a significant emphasis on writing test codes. This might be a given for a database project; however, the thoroughness of our approach is evident from our line coverage of nearly ",(0,o.yg)("strong",{parentName:"p"},"99%")," for core codes. While we devoted considerable effort to creating these test codes, our primary focus has always been on a different aspect: ensuring that anyone can quickly grasp the content of the tests and easily add new ones."),(0,o.yg)("p",null,"The intent here is to empower newcomers to GlueSQL to understand the functionality of the software solely by examining integration tests, even in the absence of a user manual."),(0,o.yg)("p",null,"The integration tests for GlueSQL can be found in the test-suite workspace. For example, here's an excerpt of the test code for the INSERT statement:"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-rust"},'test_case!(insert, async move {\n run!(\n "\nCREATE TABLE Test (\n id INTEGER DEFAULT 1,\n num INTEGER NULL,\n name TEXT NOT NULL,\n);"\n );\n\n test! {\n name: "basic insert - single item",\n sql: "INSERT INTO Test (id, num, name) VALUES (1, 2, \'Hi boo\');",\n expected: Ok(Payload::Insert(1))\n };\n\n\n test! {\n sql: "INSERT INTO Test VALUES(17, 30, \'Sullivan\');",\n expected: Ok(Payload::Insert(1))\n };\n\n test! {\n sql: "INSERT INTO Test (num, name) VALUES (28, \'Wazowski\');",\n expected: Ok(Payload::Insert(1))\n };\n\n test! {\n sql: "SELECT * FROM Test;",\n expected: Ok(select!(\n id | num | name;\n I64 | I64 | Str;\n 1 2 "Hi boo".to_owned();\n 3 9 "Kitty!".to_owned();\n 2 7 "Monsters".to_owned();\n 17 30 "Sullivan".to_owned();\n 1 28 "Wazowski".to_owned()\n ))\n };\n\n // ...\n});\n')),(0,o.yg)("p",null,"Despite being written in Rust, these test cases are designed to be comprehensible, even to those unfamiliar with the language. Each test is a complete scenario from start to finish, and the results of each operation are readily observable."),(0,o.yg)("p",null,"Given that identifying results from SELECT operations in the form of Rust enums and structs can be challenging, we actively utilized macros such as ",(0,o.yg)("inlineCode",{parentName:"p"},"select!")," and ",(0,o.yg)("inlineCode",{parentName:"p"},"select_with_null!"),". We've composed the test cases to demonstrate that the INSERT statement can handle a wide range of cases, including specifying all columns, omitting some, or omitting all."),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-rust"},'test! {\n sql: "INSERT INTO Test (id, num) VALUES (1, 10);",\n expected: Err(InsertError::LackOfRequiredColumn("name".to_owned()).into())\n};\n')),(0,o.yg)("p",null,"The tests also include scenarios for expected faulty inputs, indicating the error returns in these situations."),(0,o.yg)("p",null,"By organizing the tests in this manner, we aim to make it easy for anyone to read and write tests. Our goal was for these tests to serve as \"documentation\" for GlueSQL contributors. At the time we were writing these tests, we didn't anticipate that they could actually become documentation themselves. But we've come to realize that they have extraordinary potential."),(0,o.yg)("h2",{id:"leveraging-chatgpt"},"Leveraging ChatGPT"),(0,o.yg)("p",null,"When we first embarked on writing the User Manual, we were overwhelmed by the sheer volume of content we had to generate. Around the same time, ChatGPT was gaining prominence, and we thought it might be worth trying out, if only to lighten our load slightly."),(0,o.yg)("p",null,"To our surprise, ChatGPT exceeded our expectations. If the test codes were well written, it was capable of automatically crafting an exceptional document based on them, capturing all essential details."),(0,o.yg)("p",null,"After several trials and errors, we settled on the following prompt for document generation. While it's still a challenge to use the same prompt for all documentation, we made minor modifications to suit different situations:"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre"},"I'm creating an SQL database documentation website, and I'd like you to help me with one of the pages that introduces the SQL syntax for GlueSQL.\n\n1. Please provide the response content in the \"markdown\" format, so I can copy and paste it directly. Keep this constraint in mind while writing. \n2. Regardless of the language I use, I need the content written in English. \n3. I will provide some test case code written in the Rust language, which contains SQL examples. Please write the documentation based on these examples, but feel free to change the table names, column names, and data types as needed. Don't include any Rust related content or text in the response. all the response code example should be in plain SQL. \n4. GlueSQL does not have the VARCHAR type. If you want to use that, please use TEXT instead. You don't need to mention this in the response. \n5. Wrap the entire response text using

 and 
tags so I can copy all the content easily. \n\nNow, I'd like you to write the following request: \nSQL Statement - \"INSERT\" \n\nHere's an example test code you can refer to:\n\ntest_case!(insert, async move {\n run!(...\n")),(0,o.yg)("p",null,"Generally, we used the template above, and copied and pasted the test code from our existing test-suite. We leveraged this method to harness our many tests to assist in the creation of the user manual. In the next section, we'll showcase a sample of the documentation generated in this manner. It's quite impressive."),(0,o.yg)("h2",{id:"success-case-automated-user-manual-of-gluesql"},"Success Case: Automated User Manual of GlueSQL"),(0,o.yg)("p",null,"Thanks to ChatGPT, the resulting INSERT document page can be viewed at the following link. It's important to note that we used ChatGPT 4 for this task. Version 3.5 wasn't quite up to the task, and using version 4 was the minimum requirement."),(0,o.yg)("p",null,(0,o.yg)("a",{parentName:"p",href:"https://gluesql.org/docs/dev/sql-syntax/statements/data-manipulation/insert"},"https://gluesql.org/docs/dev/sql-syntax/statements/data-manipulation/insert")),(0,o.yg)("p",null,(0,o.yg)("img",{alt:"INSERT Statement",src:n(2354).A,width:"2203",height:"1739"})),(0,o.yg)("p",null,"The results were quite impressive. ChatGPT neatly categorized the test cases, explained the syntax, outlined constraints, and provided appropriate examples. It didn't stop there; it also skillfully recognized error test cases and incorporated them into the documentation, as shown below."),(0,o.yg)("p",null,(0,o.yg)("img",{alt:"INSERT Statement",src:n(9455).A,width:"1751",height:"353"})),(0,o.yg)("p",null,"Isn't it amazing?"),(0,o.yg)("h2",{id:"future-plans-fully-automating-documentation-generation"},"Future Plans: Fully Automating Documentation Generation"),(0,o.yg)("p",null,"While the current documentation is far from perfect and there are many aspects that can be improved, we see great potential in this approach. We believe it's entirely possible to automate the process of writing this kind of document, and writing in general."),(0,o.yg)("p",null,"In the past, documents like user manuals required a great deal of effort to maintain once they were written. If a document contained real code examples, verifying that the code still worked was often a tedious task. With the ability to automatically generate documentation as we have done here, these issues are no longer problematic."),(0,o.yg)("p",null,"Previously, you would have to write tests and then also document them separately. If you had to support multiple languages, that would be an additional task. With a tool like ChatGPT, you can automate all of this. All a developer has to do is write the tests. This alone can be sufficient. You can generate documents automatically based on the tests. Eventually, we can even support automatically translating these documents into multiple languages."),(0,o.yg)("p",null,"The GlueSQL project repository is currently hosted on GitHub and makes good use of various GitHub Actions. We envision a GitHub Action that automatically regenerates a document corresponding to a test when a user modifies the test and raises a Pull Request. Another GitHub Action could automatically translate updated documents into supported languages and create new Pull Requests. The possibilities are truly endless."),(0,o.yg)("p",null,"Not only will this help with document generation, but it will also provide clear guidelines for writing better test code. If we can automatically generate documents based on written tests, the quality of those documents can serve as an indicator of the quality of the tests themselves. This means that a document automation tool can play the role of a good reviewer for tests. It can greatly reduce the time and effort required for painstakingly reviewing the quality of each test. Developers can also write tests without pressure, evaluate their test code by looking at the generated document, and improve it."),(0,o.yg)("p",null,"Furthermore, multi-language support becomes a breeze. In my personal experience as a software engineer over the past decade, developing various products such as games, web services, and applications, I often needed to support multiple languages. Each time, there was no definite solution. The optimal approach varied depending on the situation, and there were many things to consider when entrusting translations, such as effectively communicating the context of the target service to the translator. Moreover, regularly updating content and having it retranslated into various languages was a very tedious process. While I tried to automate as much as possible by creating various tools, I was never fully satisfied. I believe ChatGPT can completely solve these issues. If there is a need to provide project-specific context, all you need to do is prepare a prompt in advance. Instead of having to rely on and wait for professional translators, we can now entrust this task to ChatGPT, and we only need a few people to review the translated content."),(0,o.yg)("p",null,"We are nearing a world where documentation is no longer a burden for developers."),(0,o.yg)("h2",{id:"conclusion-the-value-of-test-driven-documentation"},"Conclusion: The Value of Test-Driven Documentation"),(0,o.yg)("p",null,"The use of ChatGPT to generate documentation has proven a significant step forward in the GlueSQL user manual creation process. Through test-driven documentation, we've managed to automate a substantial part of the manual creation process, saving time and effort, and increasing accuracy."),(0,o.yg)("p",null,"Moreover, this process has unveiled a new potential for documentation: the possibility of fully automating document generation. We've seen that quality tests can become quality documentation with the help of AI, leading to more efficient workflows and possibly better test code as a result."),(0,o.yg)("p",null,"The journey doesn't stop here. We envision leveraging this capability further to auto-translate our documents into multiple languages, making our product more accessible to a global audience."),(0,o.yg)("p",null,"As we progress, we hope that our experience can inspire other developers to explore and embrace the benefits of AI-generated, test-driven documentation. It's not just about saving time\u2014it's about improving the way we work, communicate, and share knowledge."))}h.isMDXComponent=!0},9455:(e,t,n)=>{n.d(t,{A:()=>a});const a=n.p+"assets/images/blog-test-driven-documentation-insert-errorcase-1be5ced205cee0d2eeb56af1591440ac.jpg"},2354:(e,t,n)=>{n.d(t,{A:()=>a});const a=n.p+"assets/images/blog-test-driven-documentation-insert-7dfbb3a9123d4aa47b845b7dede97dc9.jpg"}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/26c0a43c.fc23d5e4.js b/docs/0.16.0/assets/js/26c0a43c.fc23d5e4.js new file mode 100644 index 00000000..fb20b850 --- /dev/null +++ b/docs/0.16.0/assets/js/26c0a43c.fc23d5e4.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[8799],{5680:(e,t,r)=>{r.d(t,{xA:()=>l,yg:()=>y});var n=r(6540);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function a(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var s=n.createContext({}),u=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},l=function(e){var t=u(e.components);return n.createElement(s.Provider,{value:t},e.children)},p="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,i=e.originalType,s=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),p=u(r),d=o,y=p["".concat(s,".").concat(d)]||p[d]||f[d]||i;return r?n.createElement(y,a(a({ref:t},l),{},{components:r})):n.createElement(y,a({ref:t},l))}));function y(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=r.length,a=new Array(i);a[0]=d;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c[p]="string"==typeof e?e:o,a[1]=c;for(var u=2;u{r.r(t),r.d(t,{assets:()=>s,contentTitle:()=>a,default:()=>f,frontMatter:()=>i,metadata:()=>c,toc:()=>u});var n=r(8168),o=(r(6540),r(5680));const i={},a="Type Conversion",c={unversionedId:"ast-builder/functions/others/type-conversion",id:"ast-builder/functions/others/type-conversion",title:"Type Conversion",description:"Todo",source:"@site/docs/ast-builder/functions/others/type-conversion.md",sourceDirName:"ast-builder/functions/others",slug:"/ast-builder/functions/others/type-conversion",permalink:"/docs/0.16.0/ast-builder/functions/others/type-conversion",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"Null Handling",permalink:"/docs/0.16.0/ast-builder/functions/others/null-handling"},next:{title:"Unique Identifier",permalink:"/docs/0.16.0/ast-builder/functions/others/unique-identifier"}},s={},u=[{value:"Todo",id:"todo",level:2}],l={toc:u},p="wrapper";function f(e){let{components:t,...r}=e;return(0,o.yg)(p,(0,n.A)({},l,r,{components:t,mdxType:"MDXLayout"}),(0,o.yg)("h1",{id:"type-conversion"},"Type Conversion"),(0,o.yg)("h2",{id:"todo"},"Todo"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre"},"- CAST: Converts a value from one data type to another.\n")))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/29fadaa3.5953c4d1.js b/docs/0.16.0/assets/js/29fadaa3.5953c4d1.js new file mode 100644 index 00000000..e704ce9b --- /dev/null +++ b/docs/0.16.0/assets/js/29fadaa3.5953c4d1.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[4550],{4736:e=>{e.exports=JSON.parse('{"label":"release-note","permalink":"/docs/0.16.0/blog/tags/release-note","allTagsPath":"/docs/0.16.0/blog/tags","count":2}')}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/2a4d41ed.52ff89d0.js b/docs/0.16.0/assets/js/2a4d41ed.52ff89d0.js new file mode 100644 index 00000000..ef06fa19 --- /dev/null +++ b/docs/0.16.0/assets/js/2a4d41ed.52ff89d0.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[5062],{5680:(e,t,n)=>{n.d(t,{xA:()=>g,yg:()=>m});var a=n(6540);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function l(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var p=a.createContext({}),y=function(e){var t=a.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},g=function(e){var t=y(e.components);return a.createElement(p.Provider,{value:t},e.children)},u="mdxType",s={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},c=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,p=e.parentName,g=i(e,["components","mdxType","originalType","parentName"]),u=y(n),c=r,m=u["".concat(p,".").concat(c)]||u[c]||s[c]||o;return n?a.createElement(m,l(l({ref:t},g),{},{components:n})):a.createElement(m,l({ref:t},g))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,l=new Array(o);l[0]=c;var i={};for(var p in t)hasOwnProperty.call(t,p)&&(i[p]=t[p]);i.originalType=e,i[u]="string"==typeof e?e:r,l[1]=i;for(var y=2;y{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>l,default:()=>s,frontMatter:()=>o,metadata:()=>i,toc:()=>y});var a=n(8168),r=(n(6540),n(5680));const o={},l="GET_Y",i={unversionedId:"sql-syntax/functions/geometry/get-y",id:"sql-syntax/functions/geometry/get-y",title:"GET_Y",description:"The GET_Y function returns the y-coordinate of a given POINT data type. It takes one POINT data type argument and returns a FLOAT value representing the y-coordinate.",source:"@site/docs/sql-syntax/functions/geometry/get-y.md",sourceDirName:"sql-syntax/functions/geometry",slug:"/sql-syntax/functions/geometry/get-y",permalink:"/docs/0.16.0/sql-syntax/functions/geometry/get-y",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"GET_X",permalink:"/docs/0.16.0/sql-syntax/functions/geometry/get-x"},next:{title:"POINT",permalink:"/docs/0.16.0/sql-syntax/functions/geometry/point"}},p={},y=[{value:"Syntax",id:"syntax",level:2},{value:"Examples",id:"examples",level:2},{value:"Example 1: Get the Y-coordinate from a point",id:"example-1-get-the-y-coordinate-from-a-point",level:3},{value:"Example 2: Get the Y-coordinate from a point using CAST",id:"example-2-get-the-y-coordinate-from-a-point-using-cast",level:3},{value:"Example 3: Get the Y-coordinate from a point using POINT function",id:"example-3-get-the-y-coordinate-from-a-point-using-point-function",level:3},{value:"Errors",id:"errors",level:2}],g={toc:y},u="wrapper";function s(e){let{components:t,...n}=e;return(0,r.yg)(u,(0,a.A)({},g,n,{components:t,mdxType:"MDXLayout"}),(0,r.yg)("h1",{id:"get_y"},"GET_Y"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"GET_Y")," function returns the y-coordinate of a given ",(0,r.yg)("inlineCode",{parentName:"p"},"POINT")," data type. It takes one ",(0,r.yg)("inlineCode",{parentName:"p"},"POINT")," data type argument and returns a ",(0,r.yg)("inlineCode",{parentName:"p"},"FLOAT")," value representing the y-coordinate."),(0,r.yg)("h2",{id:"syntax"},"Syntax"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"GET_Y(point)\n")),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},"Parameters:")),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"point"),": The geographical coordinate of type ",(0,r.yg)("inlineCode",{parentName:"li"},"Point")," from which the Y-coordinate will be extracted.")),(0,r.yg)("h2",{id:"examples"},"Examples"),(0,r.yg)("p",null,"Consider the following table ",(0,r.yg)("inlineCode",{parentName:"p"},"PointGroup"),":"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE PointGroup (\n point_field POINT\n);\n")),(0,r.yg)("p",null,"With the following data:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO PointGroup VALUES (POINT(0.3134, 0.156));\n")),(0,r.yg)("h3",{id:"example-1-get-the-y-coordinate-from-a-point"},"Example 1: Get the Y-coordinate from a point"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT GET_Y(point_field) AS point_field FROM PointGroup;\n")),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},"Result:")),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},"point_field"))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},"0.156")))),(0,r.yg)("h3",{id:"example-2-get-the-y-coordinate-from-a-point-using-cast"},"Example 2: Get the Y-coordinate from a point using CAST"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT GET_Y(CAST('POINT(0.1 -0.2)' AS POINT)) AS ptx;\n")),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},"Result:")),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},"ptx"))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},"-0.2")))),(0,r.yg)("h3",{id:"example-3-get-the-y-coordinate-from-a-point-using-point-function"},"Example 3: Get the Y-coordinate from a point using POINT function"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT GET_Y(POINT(0.1, -0.2)) AS ptx;\n")),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},"Result:")),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},"ptx"))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},"-0.2")))),(0,r.yg)("h2",{id:"errors"},"Errors"),(0,r.yg)("p",null,"If the argument is not of type ",(0,r.yg)("inlineCode",{parentName:"p"},"Point"),", a ",(0,r.yg)("inlineCode",{parentName:"p"},"FunctionRequiresPointValue")," error will be thrown."))}s.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/2b265210.b10c2ab1.js b/docs/0.16.0/assets/js/2b265210.b10c2ab1.js new file mode 100644 index 00000000..2bb35c18 --- /dev/null +++ b/docs/0.16.0/assets/js/2b265210.b10c2ab1.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[6257],{5680:(e,t,n)=>{n.d(t,{xA:()=>c,yg:()=>d});var r=n(6540);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var p=r.createContext({}),s=function(e){var t=r.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},c=function(e){var t=s(e.components);return r.createElement(p.Provider,{value:t},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},g=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,l=e.originalType,p=e.parentName,c=i(e,["components","mdxType","originalType","parentName"]),u=s(n),g=a,d=u["".concat(p,".").concat(g)]||u[g]||m[g]||l;return n?r.createElement(d,o(o({ref:t},c),{},{components:n})):r.createElement(d,o({ref:t},c))}));function d(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var l=n.length,o=new Array(l);o[0]=g;var i={};for(var p in t)hasOwnProperty.call(t,p)&&(i[p]=t[p]);i.originalType=e,i[u]="string"==typeof e?e:a,o[1]=i;for(var s=2;s{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>o,default:()=>m,frontMatter:()=>l,metadata:()=>i,toc:()=>s});var r=n(8168),a=(n(6540),n(5680));const l={},o="Pattern Matching",i={unversionedId:"ast-builder/expressions/pattern-matching",id:"ast-builder/expressions/pattern-matching",title:"Pattern Matching",description:"Pattern matching is a crucial feature in SQL that allows you to match rows based on specific patterns in a column. GlueSQL provides 4 pattern matching operators: like, ilike, notlike, and notilike.",source:"@site/docs/ast-builder/expressions/pattern-matching.md",sourceDirName:"ast-builder/expressions",slug:"/ast-builder/expressions/pattern-matching",permalink:"/docs/0.16.0/ast-builder/expressions/pattern-matching",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"Operator Based",permalink:"/docs/0.16.0/ast-builder/expressions/operator-based"},next:{title:"Value Checking",permalink:"/docs/0.16.0/ast-builder/expressions/value-checking"}},p={},s=[{value:"LIKE Operator",id:"like-operator",level:2},{value:"ILIKE Operator",id:"ilike-operator",level:2},{value:"NOT_LIKE Operator",id:"not_like-operator",level:2},{value:"NOT_ILIKE Operator",id:"not_ilike-operator",level:2}],c={toc:s},u="wrapper";function m(e){let{components:t,...n}=e;return(0,a.yg)(u,(0,r.A)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"pattern-matching"},"Pattern Matching"),(0,a.yg)("p",null,"Pattern matching is a crucial feature in SQL that allows you to match rows based on specific patterns in a column. GlueSQL provides 4 pattern matching operators: ",(0,a.yg)("inlineCode",{parentName:"p"},"like"),", ",(0,a.yg)("inlineCode",{parentName:"p"},"ilike"),", ",(0,a.yg)("inlineCode",{parentName:"p"},"not_like"),", and ",(0,a.yg)("inlineCode",{parentName:"p"},"not_ilike"),". "),(0,a.yg)("p",null,"Here's how you can use these operators with two special characters:"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"%"),": Matches any number of characters, including zero characters"),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"_"),": Matches exactly one character")),(0,a.yg)("h2",{id:"like-operator"},"LIKE Operator"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"like")," operator is used in a WHERE clause to search for a specified pattern in a column. "),(0,a.yg)("p",null,"Here is an example:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Category")\n .select()\n .filter(\n col("name")\n .like(text("D%"))\n .or(col("name").like(text("M___"))),\n )\n .execute(glue)\n .await;\n')),(0,a.yg)("p",null,"In this example, the query will return all rows from the ",(0,a.yg)("inlineCode",{parentName:"p"},"Category")," table where the ",(0,a.yg)("inlineCode",{parentName:"p"},"name"),' column starts with "D" or where the ',(0,a.yg)("inlineCode",{parentName:"p"},"name"),' is exactly four characters long and starts with "M".'),(0,a.yg)("h2",{id:"ilike-operator"},"ILIKE Operator"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"ilike")," operator is used in a WHERE clause to search for a specified pattern in a column, regardless of case."),(0,a.yg)("p",null,"Here is an example:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Category")\n .select()\n .filter(\n col("name")\n .ilike(text("D%"))\n .or(col("name").ilike(text("M___"))),\n )\n .execute(glue)\n .await;\n')),(0,a.yg)("p",null,"In this example, the query will return all rows from the ",(0,a.yg)("inlineCode",{parentName:"p"},"Category")," table where the ",(0,a.yg)("inlineCode",{parentName:"p"},"name"),' column starts with "D" or "d", or where the ',(0,a.yg)("inlineCode",{parentName:"p"},"name"),' is exactly four characters long and starts with "M" or "m".'),(0,a.yg)("h2",{id:"not_like-operator"},"NOT_LIKE Operator"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"not_like")," operator is used in a WHERE clause to match rows that don't follow the specific pattern."),(0,a.yg)("p",null,"Here is an example:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Category")\n .select()\n .filter(\n col("name")\n .not_like(text("D%"))\n .and(col("name").not_like(text("M___"))),\n )\n .execute(glue)\n .await;\n')),(0,a.yg)("p",null,"In this example, the query will return all rows from the ",(0,a.yg)("inlineCode",{parentName:"p"},"Category")," table where the ",(0,a.yg)("inlineCode",{parentName:"p"},"name"),' column does not start with "D" and the ',(0,a.yg)("inlineCode",{parentName:"p"},"name"),' is not exactly four characters long and does not start with "M".'),(0,a.yg)("h2",{id:"not_ilike-operator"},"NOT_ILIKE Operator"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"not_ilike")," operator is used in a WHERE clause to match rows that don't follow the specific pattern, regardless of case."),(0,a.yg)("p",null,"Here is an example:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Category")\n .select()\n .filter(\n col("name")\n .not_ilike(text("D%"))\n .and(col("name").not_ilike(text("M___"))),\n )\n .execute(glue)\n .await;\n')),(0,a.yg)("p",null,"In this example, the query will return all rows from the ",(0,a.yg)("inlineCode",{parentName:"p"},"Category")," table where the ",(0,a.yg)("inlineCode",{parentName:"p"},"name"),' column does not start with "D" or "d", and the ',(0,a.yg)("inlineCode",{parentName:"p"},"name"),' is not exactly four characters long and does not start with "M" or "m".'))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/2bb892db.7dbc4c68.js b/docs/0.16.0/assets/js/2bb892db.7dbc4c68.js new file mode 100644 index 00000000..ae417899 --- /dev/null +++ b/docs/0.16.0/assets/js/2bb892db.7dbc4c68.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[1990],{437:s=>{s.exports=JSON.parse('{"label":"v0.14","permalink":"/docs/0.16.0/blog/tags/v-0-14","allTagsPath":"/docs/0.16.0/blog/tags","count":1}')}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/2c0d2b92.f8c85258.js b/docs/0.16.0/assets/js/2c0d2b92.f8c85258.js new file mode 100644 index 00000000..30449dc0 --- /dev/null +++ b/docs/0.16.0/assets/js/2c0d2b92.f8c85258.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[8819],{5680:(e,n,t)=>{t.d(n,{xA:()=>u,yg:()=>m});var r=t(6540);function a(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function o(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function l(e){for(var n=1;n=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var i=r.createContext({}),p=function(e){var n=r.useContext(i),t=n;return e&&(t="function"==typeof e?e(n):l(l({},n),e)),t},u=function(e){var n=p(e.components);return r.createElement(i.Provider,{value:n},e.children)},c="mdxType",d={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},y=r.forwardRef((function(e,n){var t=e.components,a=e.mdxType,o=e.originalType,i=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),c=p(t),y=a,m=c["".concat(i,".").concat(y)]||c[y]||d[y]||o;return t?r.createElement(m,l(l({ref:n},u),{},{components:t})):r.createElement(m,l({ref:n},u))}));function m(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var o=t.length,l=new Array(o);l[0]=y;var s={};for(var i in n)hasOwnProperty.call(n,i)&&(s[i]=n[i]);s.originalType=e,s[c]="string"==typeof e?e:a,l[1]=s;for(var p=2;p{t.r(n),t.d(n,{assets:()=>i,contentTitle:()=>l,default:()=>d,frontMatter:()=>o,metadata:()=>s,toc:()=>p});var r=t(8168),a=(t(6540),t(5680));const o={sidebar_position:10},l="LIST",s={unversionedId:"sql-syntax/data-types/list",id:"sql-syntax/data-types/list",title:"LIST",description:"The LIST data type in GlueSQL is used to store ordered collections of elements, similar to JSON arrays. The elements can be any valid data supported by GlueSQL, such as numbers, strings, booleans, null, MAP, or even other nested LIST values. Although the input is provided in a JSON array format for convenience, it can store more than just JSON data.",source:"@site/docs/sql-syntax/data-types/list.md",sourceDirName:"sql-syntax/data-types",slug:"/sql-syntax/data-types/list",permalink:"/docs/0.16.0/sql-syntax/data-types/list",draft:!1,tags:[],version:"current",sidebarPosition:10,frontMatter:{sidebar_position:10},sidebar:"autoSidebar",previous:{title:"INTERVAL",permalink:"/docs/0.16.0/sql-syntax/data-types/interval"},next:{title:"MAP",permalink:"/docs/0.16.0/sql-syntax/data-types/map"}},i={},p=[],u={toc:p},c="wrapper";function d(e){let{components:n,...t}=e;return(0,a.yg)(c,(0,r.A)({},u,t,{components:n,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"list"},"LIST"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"LIST")," data type in GlueSQL is used to store ordered collections of elements, similar to JSON arrays. The elements can be any valid data supported by GlueSQL, such as numbers, strings, booleans, ",(0,a.yg)("inlineCode",{parentName:"p"},"null"),", ",(0,a.yg)("inlineCode",{parentName:"p"},"MAP"),", or even other nested ",(0,a.yg)("inlineCode",{parentName:"p"},"LIST")," values. Although the input is provided in a JSON array format for convenience, it can store more than just JSON data."),(0,a.yg)("p",null,"Here is an example of creating a table with a ",(0,a.yg)("inlineCode",{parentName:"p"},"LIST")," data type:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE ListType (\n id INTEGER,\n items LIST\n);\n")),(0,a.yg)("p",null,"You can insert data into the table using JSON-like syntax:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},'INSERT INTO ListType VALUES\n (1, \'[1, 2, 3]\'),\n (2, \'["hello", "world", 30, true, [9,8]]\'),\n (3, \'[{ "foo": 100, "bar": [true, 0, [10.5, false] ] }, 10, 20]\');\n')),(0,a.yg)("p",null,"To access the elements in a ",(0,a.yg)("inlineCode",{parentName:"p"},"LIST"),", you can use the index operator ",(0,a.yg)("inlineCode",{parentName:"p"},"[]"),":"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT id, items[1] AS second FROM ListType;\n")),(0,a.yg)("p",null,"This query would return the following result:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre"}," id | second\n----|--------\n 1 | 2\n 2 | world\n 3 | 10\n")),(0,a.yg)("p",null,"You can also access nested elements using the index operator, like this:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT id, items[3][0] AS hundred FROM ListType2;\n")),(0,a.yg)("p",null,"This query would return the following result:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre"}," id | hundred\n----|--------\n 1 | null\n 2 | 100\n 3 | null\n")),(0,a.yg)("p",null,"If a specified index is out of range or the element is not a ",(0,a.yg)("inlineCode",{parentName:"p"},"MAP")," or ",(0,a.yg)("inlineCode",{parentName:"p"},"LIST"),", the result will be ",(0,a.yg)("inlineCode",{parentName:"p"},"null"),"."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/2d9479c4.60ec37b5.js b/docs/0.16.0/assets/js/2d9479c4.60ec37b5.js new file mode 100644 index 00000000..f9ef0d89 --- /dev/null +++ b/docs/0.16.0/assets/js/2d9479c4.60ec37b5.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[1459],{5680:(e,n,t)=>{t.d(n,{xA:()=>u,yg:()=>m});var r=t(6540);function a(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function o(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function s(e){for(var n=1;n=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var l=r.createContext({}),p=function(e){var n=r.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):s(s({},n),e)),t},u=function(e){var n=p(e.components);return r.createElement(l.Provider,{value:n},e.children)},c="mdxType",E={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},d=r.forwardRef((function(e,n){var t=e.components,a=e.mdxType,o=e.originalType,l=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),c=p(t),d=a,m=c["".concat(l,".").concat(d)]||c[d]||E[d]||o;return t?r.createElement(m,s(s({ref:n},u),{},{components:t})):r.createElement(m,s({ref:n},u))}));function m(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var o=t.length,s=new Array(o);s[0]=d;var i={};for(var l in n)hasOwnProperty.call(n,l)&&(i[l]=n[l]);i.originalType=e,i[c]="string"==typeof e?e:a,s[1]=i;for(var p=2;p{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>s,default:()=>E,frontMatter:()=>o,metadata:()=>i,toc:()=>p});var r=t(8168),a=(t(6540),t(5680));const o={sidebar_position:1},s="WHERE",i={unversionedId:"sql-syntax/statements/querying/where",id:"sql-syntax/statements/querying/where",title:"WHERE",description:"In GlueSQL, the WHERE clause is used to filter the results of a SELECT query based on specific conditions. The WHERE clause can be used with various operators and functions to create complex filtering conditions.",source:"@site/docs/sql-syntax/statements/querying/where.md",sourceDirName:"sql-syntax/statements/querying",slug:"/sql-syntax/statements/querying/where",permalink:"/docs/0.16.0/sql-syntax/statements/querying/where",draft:!1,tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"autoSidebar",previous:{title:"Introduction",permalink:"/docs/0.16.0/sql-syntax/intro"},next:{title:"JOIN",permalink:"/docs/0.16.0/sql-syntax/statements/querying/join"}},l={},p=[{value:"Comparison Operators",id:"comparison-operators",level:2},{value:"BETWEEN Operator",id:"between-operator",level:2},{value:"EXISTS and NOT EXISTS",id:"exists-and-not-exists",level:2},{value:"IN Operator",id:"in-operator",level:2},{value:"LIKE and ILIKE Operators",id:"like-and-ilike-operators",level:2}],u={toc:p},c="wrapper";function E(e){let{components:n,...t}=e;return(0,a.yg)(c,(0,r.A)({},u,t,{components:n,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"where"},"WHERE"),(0,a.yg)("p",null,"In GlueSQL, the ",(0,a.yg)("inlineCode",{parentName:"p"},"WHERE")," clause is used to filter the results of a ",(0,a.yg)("inlineCode",{parentName:"p"},"SELECT")," query based on specific conditions. The ",(0,a.yg)("inlineCode",{parentName:"p"},"WHERE")," clause can be used with various operators and functions to create complex filtering conditions."),(0,a.yg)("p",null,"Here are some examples based on the provided Rust test code and SQL queries:"),(0,a.yg)("h2",{id:"comparison-operators"},"Comparison Operators"),(0,a.yg)("p",null,"You can use comparison operators such as ",(0,a.yg)("inlineCode",{parentName:"p"},"="),", ",(0,a.yg)("inlineCode",{parentName:"p"},"<>"),", ",(0,a.yg)("inlineCode",{parentName:"p"},"<"),", ",(0,a.yg)("inlineCode",{parentName:"p"},">"),", ",(0,a.yg)("inlineCode",{parentName:"p"},"<="),", and ",(0,a.yg)("inlineCode",{parentName:"p"},">=")," to compare values in the ",(0,a.yg)("inlineCode",{parentName:"p"},"WHERE")," clause."),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT name FROM Boss WHERE id <= 2;\nSELECT name FROM Boss WHERE +id <= 2;\n")),(0,a.yg)("h2",{id:"between-operator"},"BETWEEN Operator"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"BETWEEN")," operator allows you to filter results within a specific range."),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT id, name FROM Boss WHERE id BETWEEN 2 AND 4;\nSELECT id, name FROM Boss WHERE name BETWEEN 'Doll' AND 'Gehrman';\n")),(0,a.yg)("p",null,"To exclude the specified range, use the ",(0,a.yg)("inlineCode",{parentName:"p"},"NOT BETWEEN")," operator."),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT name FROM Boss WHERE name NOT BETWEEN 'Doll' AND 'Gehrman';\n")),(0,a.yg)("h2",{id:"exists-and-not-exists"},"EXISTS and NOT EXISTS"),(0,a.yg)("p",null,(0,a.yg)("inlineCode",{parentName:"p"},"EXISTS")," and ",(0,a.yg)("inlineCode",{parentName:"p"},"NOT EXISTS")," operators are used to filter results based on the existence of records in a subquery."),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT name\nFROM Boss\nWHERE EXISTS (\n SELECT * FROM Hunter WHERE Hunter.name = Boss.name\n);\n\nSELECT name\nFROM Boss\nWHERE NOT EXISTS (\n SELECT * FROM Hunter WHERE Hunter.name = Boss.name\n);\n")),(0,a.yg)("h2",{id:"in-operator"},"IN Operator"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"IN")," operator allows you to filter results based on a list of values or a subquery."),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT * FROM Player WHERE id IN (SELECT user_id FROM Request WHERE quantity IN (6, 7, 8, 9));\n")),(0,a.yg)("h2",{id:"like-and-ilike-operators"},"LIKE and ILIKE Operators"),(0,a.yg)("p",null,(0,a.yg)("inlineCode",{parentName:"p"},"LIKE")," and ",(0,a.yg)("inlineCode",{parentName:"p"},"ILIKE")," operators are used to filter results based on pattern matching. Use the ",(0,a.yg)("inlineCode",{parentName:"p"},"%")," wildcard to match any number of characters and the ",(0,a.yg)("inlineCode",{parentName:"p"},"_")," wildcard to match a single character."),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT name FROM Item WHERE name LIKE '_a%';\nSELECT name FROM Item WHERE name LIKE '%r%';\n")),(0,a.yg)("p",null,(0,a.yg)("inlineCode",{parentName:"p"},"ILIKE")," is a case-insensitive version of ",(0,a.yg)("inlineCode",{parentName:"p"},"LIKE"),"."),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT name FROM Item WHERE name ILIKE '%%';\nSELECT name FROM Item WHERE name NOT ILIKE '%A%';\n")))}E.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/2f7bd5c8.56754015.js b/docs/0.16.0/assets/js/2f7bd5c8.56754015.js new file mode 100644 index 00000000..efb2c2e2 --- /dev/null +++ b/docs/0.16.0/assets/js/2f7bd5c8.56754015.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[3848],{5680:(e,n,t)=>{t.d(n,{xA:()=>c,yg:()=>y});var a=t(6540);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function l(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function s(e){for(var n=1;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var o=a.createContext({}),u=function(e){var n=a.useContext(o),t=n;return e&&(t="function"==typeof e?e(n):s(s({},n),e)),t},c=function(e){var n=u(e.components);return a.createElement(o.Provider,{value:n},e.children)},p="mdxType",g={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},m=a.forwardRef((function(e,n){var t=e.components,r=e.mdxType,l=e.originalType,o=e.parentName,c=i(e,["components","mdxType","originalType","parentName"]),p=u(t),m=r,y=p["".concat(o,".").concat(m)]||p[m]||g[m]||l;return t?a.createElement(y,s(s({ref:n},c),{},{components:t})):a.createElement(y,s({ref:n},c))}));function y(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var l=t.length,s=new Array(l);s[0]=m;var i={};for(var o in n)hasOwnProperty.call(n,o)&&(i[o]=n[o]);i.originalType=e,i[p]="string"==typeof e?e:r,s[1]=i;for(var u=2;u{t.r(n),t.d(n,{assets:()=>o,contentTitle:()=>s,default:()=>g,frontMatter:()=>l,metadata:()=>i,toc:()=>u});var a=t(8168),r=(t(6540),t(5680));const l={},s="COS",i={unversionedId:"sql-syntax/functions/math/cos",id:"sql-syntax/functions/math/cos",title:"COS",description:"The COS function is used to calculate the cosine of a number. It takes a single numeric argument (angle in radians) and returns the cosine of that angle.",source:"@site/docs/sql-syntax/functions/math/cos.md",sourceDirName:"sql-syntax/functions/math",slug:"/sql-syntax/functions/math/cos",permalink:"/docs/0.16.0/sql-syntax/functions/math/cos",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"CEIL",permalink:"/docs/0.16.0/sql-syntax/functions/math/ceil"},next:{title:"DEGREES",permalink:"/docs/0.16.0/sql-syntax/functions/math/degrees"}},o={},u=[{value:"Syntax",id:"syntax",level:2},{value:"Examples",id:"examples",level:2},{value:"Example 1: Using COS with float values",id:"example-1-using-cos-with-float-values",level:3},{value:"Example 2: Using COS with NULL values",id:"example-2-using-cos-with-null-values",level:3},{value:"Errors",id:"errors",level:2},{value:"Example 3: Using COS with non-numeric values",id:"example-3-using-cos-with-non-numeric-values",level:3},{value:"Example 4: Using COS with multiple arguments",id:"example-4-using-cos-with-multiple-arguments",level:3}],c={toc:u},p="wrapper";function g(e){let{components:n,...t}=e;return(0,r.yg)(p,(0,a.A)({},c,t,{components:n,mdxType:"MDXLayout"}),(0,r.yg)("h1",{id:"cos"},"COS"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"COS")," function is used to calculate the cosine of a number. It takes a single numeric argument (angle in radians) and returns the cosine of that angle."),(0,r.yg)("h2",{id:"syntax"},"Syntax"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"COS(value)\n")),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"value"),": A numeric expression (angle in radians) for which the cosine is to be calculated.")),(0,r.yg)("h2",{id:"examples"},"Examples"),(0,r.yg)("p",null,"Let's consider a table named ",(0,r.yg)("inlineCode",{parentName:"p"},"SingleItem")," with the following schema:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE SingleItem (id INTEGER);\n")),(0,r.yg)("p",null,"Insert a row into the ",(0,r.yg)("inlineCode",{parentName:"p"},"SingleItem")," table:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO SingleItem VALUES (0);\n")),(0,r.yg)("h3",{id:"example-1-using-cos-with-float-values"},"Example 1: Using COS with float values"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT COS(0.5) AS cos1, COS(1) AS cos2 FROM SingleItem;\n")),(0,r.yg)("p",null,"Result:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre"}," cos1 | cos2\n-------------+--------------\n 0.877582562 | 0.540302306\n")),(0,r.yg)("h3",{id:"example-2-using-cos-with-null-values"},"Example 2: Using COS with NULL values"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT COS(NULL) AS cos FROM SingleItem;\n")),(0,r.yg)("p",null,"Result:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre"}," cos\n-------\n (null)\n")),(0,r.yg)("h2",{id:"errors"},"Errors"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"COS")," function requires a numeric value as its argument. Using non-numeric values or more than one argument will result in an error."),(0,r.yg)("h3",{id:"example-3-using-cos-with-non-numeric-values"},"Example 3: Using COS with non-numeric values"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT COS('string') AS cos FROM SingleItem;\n")),(0,r.yg)("p",null,"Error: Function requires a numeric value."),(0,r.yg)("h3",{id:"example-4-using-cos-with-multiple-arguments"},"Example 4: Using COS with multiple arguments"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT COS(1.0, 2.0) AS cos FROM SingleItem;\n")),(0,r.yg)("p",null,"Error: Function expects 1 argument, but 2 were provided."))}g.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/31526b20.042cabc1.js b/docs/0.16.0/assets/js/31526b20.042cabc1.js new file mode 100644 index 00000000..43c4abbf --- /dev/null +++ b/docs/0.16.0/assets/js/31526b20.042cabc1.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[2920],{5680:(e,t,n)=>{n.d(t,{xA:()=>c,yg:()=>y});var a=n(6540);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=a.createContext({}),u=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},c=function(e){var t=u(e.components);return a.createElement(s.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},g=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),p=u(n),g=r,y=p["".concat(s,".").concat(g)]||p[g]||d[g]||i;return n?a.createElement(y,o(o({ref:t},c),{},{components:n})):a.createElement(y,o({ref:t},c))}));function y(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,o=new Array(i);o[0]=g;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[p]="string"==typeof e?e:r,o[1]=l;for(var u=2;u{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>d,frontMatter:()=>i,metadata:()=>l,toc:()=>u});var a=n(8168),r=(n(6540),n(5680));const i={title:"Introduction",sidebar_position:1},o="SQL Syntax",l={unversionedId:"sql-syntax/intro",id:"sql-syntax/intro",title:"Introduction",description:"Welcome to the Introduction page for the SQL Syntax category in GlueSQL! In this section, we'll provide a brief overview of the SQL syntax supported by GlueSQL. You can find more in-depth examples and details by browsing the other pages in this category.",source:"@site/docs/sql-syntax/intro.md",sourceDirName:"sql-syntax",slug:"/sql-syntax/intro",permalink:"/docs/0.16.0/sql-syntax/intro",draft:!1,tags:[],version:"current",sidebarPosition:1,frontMatter:{title:"Introduction",sidebar_position:1},sidebar:"autoSidebar",previous:{title:"Command-Line Interface",permalink:"/docs/0.16.0/getting-started/cli"},next:{title:"WHERE",permalink:"/docs/0.16.0/sql-syntax/statements/querying/where"}},s={},u=[{value:"Creating Tables",id:"creating-tables",level:2},{value:"Inserting Data",id:"inserting-data",level:2},{value:"Selecting Data",id:"selecting-data",level:2},{value:"Updating Data",id:"updating-data",level:2},{value:"Deleting Data",id:"deleting-data",level:2}],c={toc:u},p="wrapper";function d(e){let{components:t,...n}=e;return(0,r.yg)(p,(0,a.A)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,r.yg)("h1",{id:"sql-syntax"},"SQL Syntax"),(0,r.yg)("p",null,"Welcome to the Introduction page for the SQL Syntax category in GlueSQL! In this section, we'll provide a brief overview of the SQL syntax supported by GlueSQL. You can find more in-depth examples and details by browsing the other pages in this category."),(0,r.yg)("p",null,"GlueSQL is a SQL database engine written in Rust, designed to be lightweight, fast, and easy to integrate with various data storage systems. It supports a wide range of SQL features, including creating and managing tables, inserting and updating data, and performing various types of queries."),(0,r.yg)("p",null,"Here's a list of some basic SQL statements you can use with GlueSQL:"),(0,r.yg)("h2",{id:"creating-tables"},"Creating Tables"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE table_name (\n column_name1 data_type1,\n column_name2 data_type2,\n ...\n);\n")),(0,r.yg)("h2",{id:"inserting-data"},"Inserting Data"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO table_name (column1, column2, ...) VALUES (value1, value2, ...);\n")),(0,r.yg)("h2",{id:"selecting-data"},"Selecting Data"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT column1, column2, ... FROM table_name WHERE conditions;\n")),(0,r.yg)("h2",{id:"updating-data"},"Updating Data"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"UPDATE table_name SET column1 = value1, column2 = value2, ... WHERE conditions;\n")),(0,r.yg)("h2",{id:"deleting-data"},"Deleting Data"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"DELETE FROM table_name WHERE conditions;\n")),(0,r.yg)("p",null,"For a complete list of supported SQL features, you can visit the GlueSQL GitHub repository's test suite folder, even if you're not familiar with Rust code:\n",(0,r.yg)("a",{parentName:"p",href:"https://github.com/gluesql/gluesql/tree/main/test-suite/src"},"https://github.com/gluesql/gluesql/tree/main/test-suite/src")),(0,r.yg)("p",null,"This folder contains tests for all the functionalities supported by GlueSQL, providing you with an extensive reference for syntax and usage."),(0,r.yg)("p",null,"Feel free to explore the other pages in this category to dive deeper into GlueSQL's SQL syntax and capabilities!"))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/3245f64b.3f312bbc.js b/docs/0.16.0/assets/js/3245f64b.3f312bbc.js new file mode 100644 index 00000000..a57a5edc --- /dev/null +++ b/docs/0.16.0/assets/js/3245f64b.3f312bbc.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[9327],{5680:(e,t,n)=>{n.d(t,{xA:()=>p,yg:()=>m});var a=n(6540);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=a.createContext({}),u=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=u(e.components);return a.createElement(s.Provider,{value:t},e.children)},c="mdxType",g={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},y=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),c=u(n),y=r,m=c["".concat(s,".").concat(y)]||c[y]||g[y]||i;return n?a.createElement(m,o(o({ref:t},p),{},{components:n})):a.createElement(m,o({ref:t},p))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,o=new Array(i);o[0]=y;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:r,o[1]=l;for(var u=2;u{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>g,frontMatter:()=>i,metadata:()=>l,toc:()=>u});var a=n(8168),r=(n(6540),n(5680));const i={sidebar_position:4},o="Aggregation",l={unversionedId:"sql-syntax/statements/querying/aggregation",id:"sql-syntax/statements/querying/aggregation",title:"Aggregation",description:"GlueSQL supports several aggregate functions to perform calculations on a set of values. Below is a list of supported aggregate functions along with a brief explanation of each:",source:"@site/docs/sql-syntax/statements/querying/aggregation.md",sourceDirName:"sql-syntax/statements/querying",slug:"/sql-syntax/statements/querying/aggregation",permalink:"/docs/0.16.0/sql-syntax/statements/querying/aggregation",draft:!1,tags:[],version:"current",sidebarPosition:4,frontMatter:{sidebar_position:4},sidebar:"autoSidebar",previous:{title:"LIMIT & OFFSET",permalink:"/docs/0.16.0/sql-syntax/statements/querying/limit"},next:{title:"Schemaless Data",permalink:"/docs/0.16.0/sql-syntax/statements/querying/schemaless"}},s={},u=[{value:"GROUP BY",id:"group-by",level:2},{value:"HAVING",id:"having",level:2}],p={toc:u},c="wrapper";function g(e){let{components:t,...n}=e;return(0,r.yg)(c,(0,a.A)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,r.yg)("h1",{id:"aggregation"},"Aggregation"),(0,r.yg)("p",null,"GlueSQL supports several aggregate functions to perform calculations on a set of values. Below is a list of supported aggregate functions along with a brief explanation of each:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"COUNT"),": Counts the number of non-NULL values in the specified column."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"AVG"),": Calculates the average of non-NULL values in the specified column."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"SUM"),": Calculates the sum of non-NULL values in the specified column."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"MAX"),": Returns the maximum value in the specified column."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"MIN"),": Returns the minimum value in the specified column."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"STDEV"),": Calculates the population standard deviation of non-NULL values in the specified column."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"VARIANCE"),": Calculates the population variance of non-NULL values in the specified column.")),(0,r.yg)("p",null,"In addition to the aggregate functions, you can use ",(0,r.yg)("inlineCode",{parentName:"p"},"GROUP BY")," and ",(0,r.yg)("inlineCode",{parentName:"p"},"HAVING")," clauses to group and filter the results based on specific conditions."),(0,r.yg)("h2",{id:"group-by"},"GROUP BY"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"GROUP BY")," clause is used to group rows with the same values in specified columns into a set of summary rows. It is often used with aggregate functions to perform calculations on each group of rows."),(0,r.yg)("p",null,"Here's an example that groups the items by ",(0,r.yg)("inlineCode",{parentName:"p"},"city")," and calculates the sum of ",(0,r.yg)("inlineCode",{parentName:"p"},"quantity")," and the count of items for each city:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT SUM(quantity), COUNT(*), city FROM Item GROUP BY city;\n")),(0,r.yg)("h2",{id:"having"},"HAVING"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"HAVING")," clause is used to filter the results of a ",(0,r.yg)("inlineCode",{parentName:"p"},"GROUP BY")," query based on a condition that applies to the summary rows. It is similar to the ",(0,r.yg)("inlineCode",{parentName:"p"},"WHERE")," clause but operates on the results of the grouping."),(0,r.yg)("p",null,"Here's an example that groups the items by ",(0,r.yg)("inlineCode",{parentName:"p"},"city")," and calculates the sum of ",(0,r.yg)("inlineCode",{parentName:"p"},"quantity")," and the count of items for each city, but only includes cities with a count greater than 1:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT SUM(quantity), COUNT(*), city FROM Item GROUP BY city HAVING COUNT(*) > 1;\n")),(0,r.yg)("p",null,"In the examples provided, you can see the usage of ",(0,r.yg)("inlineCode",{parentName:"p"},"GROUP BY")," and ",(0,r.yg)("inlineCode",{parentName:"p"},"HAVING")," clauses in combination with aggregate functions to retrieve data from the ",(0,r.yg)("inlineCode",{parentName:"p"},"Item")," table."))}g.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/345c600d.d35af627.js b/docs/0.16.0/assets/js/345c600d.d35af627.js new file mode 100644 index 00000000..70294737 --- /dev/null +++ b/docs/0.16.0/assets/js/345c600d.d35af627.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[8],{5680:(e,t,n)=>{n.d(t,{xA:()=>m,yg:()=>y});var a=n(6540);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=a.createContext({}),u=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},m=function(e){var t=u(e.components);return a.createElement(l.Provider,{value:t},e.children)},p="mdxType",g={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,l=e.parentName,m=s(e,["components","mdxType","originalType","parentName"]),p=u(n),d=r,y=p["".concat(l,".").concat(d)]||p[d]||g[d]||i;return n?a.createElement(y,o(o({ref:t},m),{},{components:n})):a.createElement(y,o({ref:t},m))}));function y(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,o=new Array(i);o[0]=d;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[p]="string"==typeof e?e:r,o[1]=s;for(var u=2;u{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>o,default:()=>g,frontMatter:()=>i,metadata:()=>s,toc:()=>u});var a=n(8168),r=(n(6540),n(5680));const i={sidebar_position:3},o="Using the Test Suite",s={unversionedId:"storages/developing-custom-storages/using-test-suite",id:"storages/developing-custom-storages/using-test-suite",title:"Using the Test Suite",description:"The GlueSQL Test Suite is a valuable tool for validating your custom storage implementation. By using the provided test sets, you can ensure that your storage implementation adheres to the required specifications and works as expected with GlueSQL.",source:"@site/docs/storages/developing-custom-storages/using-test-suite.md",sourceDirName:"storages/developing-custom-storages",slug:"/storages/developing-custom-storages/using-test-suite",permalink:"/docs/0.16.0/storages/developing-custom-storages/using-test-suite",draft:!1,tags:[],version:"current",sidebarPosition:3,frontMatter:{sidebar_position:3},sidebar:"autoSidebar",previous:{title:"Metadata",permalink:"/docs/0.16.0/storages/developing-custom-storages/store-traits/metadata"}},l={},u=[],m={toc:u},p="wrapper";function g(e){let{components:t,...n}=e;return(0,r.yg)(p,(0,a.A)({},m,n,{components:t,mdxType:"MDXLayout"}),(0,r.yg)("h1",{id:"using-the-test-suite"},"Using the Test Suite"),(0,r.yg)("p",null,"The GlueSQL Test Suite is a valuable tool for validating your custom storage implementation. By using the provided test sets, you can ensure that your storage implementation adheres to the required specifications and works as expected with GlueSQL."),(0,r.yg)("p",null,"To use the Test Suite, you will need to implement the ",(0,r.yg)("inlineCode",{parentName:"p"},"Tester")," trait for your custom storage. A great reference for this process is the ",(0,r.yg)("inlineCode",{parentName:"p"},"MemoryStorage")," implementation in the GlueSQL source code. Here's an example of how the ",(0,r.yg)("inlineCode",{parentName:"p"},"MemoryStorage")," implementation looks like:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-rust"},"use {\n async_trait::async_trait, gluesql_core::prelude::Glue, gluesql_memory_storage::MemoryStorage,\n test_suite::*,\n};\n\nstruct MemoryTester {\n glue: Glue,\n}\n\n#[async_trait(?Send)]\nimpl Tester for MemoryTester {\n async fn new(_: &str) -> Self {\n let storage = MemoryStorage::default();\n let glue = Glue::new(storage);\n\n MemoryTester { glue }\n }\n\n fn get_glue(&mut self) -> &mut Glue {\n &mut self.glue\n }\n}\n")),(0,r.yg)("p",null,"Once you have implemented the ",(0,r.yg)("inlineCode",{parentName:"p"},"Tester")," trait, you can easily add the relevant test sets for the traits you have implemented in your custom storage. Here's how the ",(0,r.yg)("inlineCode",{parentName:"p"},"MemoryStorage")," implementation adds the test sets:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-rust"},"generate_store_tests!(tokio::test, MemoryTester);\n\ngenerate_alter_table_tests!(tokio::test, MemoryTester);\n\ngenerate_metadata_table_tests!(tokio::test, MemoryTester);\n\ngenerate_custom_function_tests!(tokio::test, MemoryTester);\n")),(0,r.yg)("p",null,"The MemoryStorage example demonstrates the use of the four test sets from the Test Suite, indicating that it has implemented the ",(0,r.yg)("inlineCode",{parentName:"p"},"Store"),", ",(0,r.yg)("inlineCode",{parentName:"p"},"StoreMut"),", ",(0,r.yg)("inlineCode",{parentName:"p"},"AlterTable"),", ",(0,r.yg)("inlineCode",{parentName:"p"},"CustomFunction"),", ",(0,r.yg)("inlineCode",{parentName:"p"},"CustomFunctionMut"),", and ",(0,r.yg)("inlineCode",{parentName:"p"},"Metadata")," traits. However, you don't need to implement all Store traits for your custom storage. Instead, you can choose to implement only the traits that are relevant to your use case, and use the corresponding test sets from the Test Suite for validation."),(0,r.yg)("p",null,"The Test Suite provides test sets for the following traits:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"generate_store_tests!")," - Tests for ",(0,r.yg)("inlineCode",{parentName:"li"},"Store")," and ",(0,r.yg)("inlineCode",{parentName:"li"},"StoreMut")," implementations. (Note that ",(0,r.yg)("inlineCode",{parentName:"li"},"Store")," and ",(0,r.yg)("inlineCode",{parentName:"li"},"StoreMut")," are required for all other test sets.)"),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"generate_alter_table_tests!")," - Tests for the ",(0,r.yg)("inlineCode",{parentName:"li"},"AlterTable")," trait implementation."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"generate_custom_function_tests!")," - Tests for the ",(0,r.yg)("inlineCode",{parentName:"li"},"CustomFunction")," and ",(0,r.yg)("inlineCode",{parentName:"li"},"CustomFunctionMut")," trait implementations."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"generate_index_tests!")," - Tests for the ",(0,r.yg)("inlineCode",{parentName:"li"},"Index")," and ",(0,r.yg)("inlineCode",{parentName:"li"},"IndexMut")," trait implementations."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"generate_transaction_tests!")," - Tests for the ",(0,r.yg)("inlineCode",{parentName:"li"},"Transaction")," trait implementation."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"generate_metadata_table_tests!")," - Tests for the ",(0,r.yg)("inlineCode",{parentName:"li"},"Metadata")," trait implementation.")),(0,r.yg)("p",null,"Additionally, the Test Suite provides combined test sets for cases where you have implemented multiple optional traits:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"generate_alter_table_index_tests!")," - Tests for the ",(0,r.yg)("inlineCode",{parentName:"li"},"AlterTable"),", ",(0,r.yg)("inlineCode",{parentName:"li"},"Index"),", and ",(0,r.yg)("inlineCode",{parentName:"li"},"IndexMut")," trait implementations."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"generate_transaction_alter_table_tests!")," - Tests for the ",(0,r.yg)("inlineCode",{parentName:"li"},"Transaction")," and ",(0,r.yg)("inlineCode",{parentName:"li"},"AlterTable")," trait implementations."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"generate_transaction_index_tests!")," - Tests for the ",(0,r.yg)("inlineCode",{parentName:"li"},"Transaction"),", ",(0,r.yg)("inlineCode",{parentName:"li"},"Index"),", and ",(0,r.yg)("inlineCode",{parentName:"li"},"IndexMut")," trait implementations."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"generate_metadata_index_tests!")," - Tests for the ",(0,r.yg)("inlineCode",{parentName:"li"},"Metadata"),", ",(0,r.yg)("inlineCode",{parentName:"li"},"Index"),", and ",(0,r.yg)("inlineCode",{parentName:"li"},"IndexMut")," trait implementations.")),(0,r.yg)("p",null,"In summary, the GlueSQL Test Suite is an essential tool for validating your custom storage implementation. By using the provided test sets and the ",(0,r.yg)("inlineCode",{parentName:"p"},"MemoryStorage")," implementation as an example, you can ensure your storage works correctly with GlueSQL and adheres to the necessary specifications."))}g.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/376759eb.a26c2de9.js b/docs/0.16.0/assets/js/376759eb.a26c2de9.js new file mode 100644 index 00000000..27756796 --- /dev/null +++ b/docs/0.16.0/assets/js/376759eb.a26c2de9.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[3995],{5680:(e,t,a)=>{a.d(t,{xA:()=>c,yg:()=>g});var n=a(6540);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function l(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function o(e){for(var t=1;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var s=n.createContext({}),d=function(e){var t=n.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},c=function(e){var t=d(e.components);return n.createElement(s.Provider,{value:t},e.children)},u="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,l=e.originalType,s=e.parentName,c=i(e,["components","mdxType","originalType","parentName"]),u=d(a),m=r,g=u["".concat(s,".").concat(m)]||u[m]||p[m]||l;return a?n.createElement(g,o(o({ref:t},c),{},{components:a})):n.createElement(g,o({ref:t},c))}));function g(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var l=a.length,o=new Array(l);o[0]=m;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i[u]="string"==typeof e?e:r,o[1]=i;for(var d=2;d{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>p,frontMatter:()=>l,metadata:()=>i,toc:()=>d});var n=a(8168),r=(a(6540),a(5680));const l={sidebar_position:5},o="Deleting Data",i={unversionedId:"ast-builder/statements/data-manipulation/deleting-data",id:"ast-builder/statements/data-manipulation/deleting-data",title:"Deleting Data",description:"In this section, we will discuss how to delete data from a table using GlueSQL.",source:"@site/docs/ast-builder/statements/data-manipulation/deleting-data.md",sourceDirName:"ast-builder/statements/data-manipulation",slug:"/ast-builder/statements/data-manipulation/deleting-data",permalink:"/docs/0.16.0/ast-builder/statements/data-manipulation/deleting-data",draft:!1,tags:[],version:"current",sidebarPosition:5,frontMatter:{sidebar_position:5},sidebar:"autoSidebar",previous:{title:"Updating Data",permalink:"/docs/0.16.0/ast-builder/statements/data-manipulation/updating-data"},next:{title:"Conditional",permalink:"/docs/0.16.0/ast-builder/expressions/conditional"}},s={},d=[{value:"Delete with Filter",id:"delete-with-filter",level:2},{value:"Delete All Rows",id:"delete-all-rows",level:2}],c={toc:d},u="wrapper";function p(e){let{components:t,...a}=e;return(0,r.yg)(u,(0,n.A)({},c,a,{components:t,mdxType:"MDXLayout"}),(0,r.yg)("h1",{id:"deleting-data"},"Deleting Data"),(0,r.yg)("p",null,"In this section, we will discuss how to delete data from a table using GlueSQL."),(0,r.yg)("h2",{id:"delete-with-filter"},"Delete with Filter"),(0,r.yg)("p",null,"To delete specific rows from a table, you can use the ",(0,r.yg)("inlineCode",{parentName:"p"},"delete")," method on a table object, followed by the ",(0,r.yg)("inlineCode",{parentName:"p"},"filter")," method to provide a condition that the rows must meet. You can then use the ",(0,r.yg)("inlineCode",{parentName:"p"},"execute")," method to apply the changes."),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Foo")\n .delete()\n .filter(col("flag").eq(false))\n .execute(glue)\n .await;\nlet expected = Ok(Payload::Delete(1));\ntest(actual, expected);\n')),(0,r.yg)("p",null,"This code deletes the rows in the table ",(0,r.yg)("inlineCode",{parentName:"p"},"Foo")," where the ",(0,r.yg)("inlineCode",{parentName:"p"},"flag")," column value is false."),(0,r.yg)("h2",{id:"delete-all-rows"},"Delete All Rows"),(0,r.yg)("p",null,"To delete all rows from a table, you can use the ",(0,r.yg)("inlineCode",{parentName:"p"},"delete")," method on a table object, followed by the ",(0,r.yg)("inlineCode",{parentName:"p"},"execute")," method."),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Foo").delete().execute(glue).await;\nlet expected = Ok(Payload::Delete(2));\ntest(actual, expected);\n')),(0,r.yg)("p",null,"This code deletes all rows from the table ",(0,r.yg)("inlineCode",{parentName:"p"},"Foo"),"."))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/382b9f11.ecb346c2.js b/docs/0.16.0/assets/js/382b9f11.ecb346c2.js new file mode 100644 index 00000000..d243df98 --- /dev/null +++ b/docs/0.16.0/assets/js/382b9f11.ecb346c2.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[9445],{5368:s=>{s.exports=JSON.parse('{"label":"gluesql","permalink":"/docs/0.16.0/blog/tags/gluesql","allTagsPath":"/docs/0.16.0/blog/tags","count":1}')}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/385623dc.79e6e52e.js b/docs/0.16.0/assets/js/385623dc.79e6e52e.js new file mode 100644 index 00000000..91958ed6 --- /dev/null +++ b/docs/0.16.0/assets/js/385623dc.79e6e52e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[521],{5680:(e,n,t)=>{t.d(n,{xA:()=>c,yg:()=>y});var r=t(6540);function a(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function o(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function i(e){for(var n=1;n=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var s=r.createContext({}),u=function(e){var n=r.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},c=function(e){var n=u(e.components);return r.createElement(s.Provider,{value:n},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},m=r.forwardRef((function(e,n){var t=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),p=u(t),m=a,y=p["".concat(s,".").concat(m)]||p[m]||d[m]||o;return t?r.createElement(y,i(i({ref:n},c),{},{components:t})):r.createElement(y,i({ref:n},c))}));function y(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var o=t.length,i=new Array(o);i[0]=m;var l={};for(var s in n)hasOwnProperty.call(n,s)&&(l[s]=n[s]);l.originalType=e,l[p]="string"==typeof e?e:a,i[1]=l;for(var u=2;u{t.r(n),t.d(n,{assets:()=>s,contentTitle:()=>i,default:()=>d,frontMatter:()=>o,metadata:()=>l,toc:()=>u});var r=t(8168),a=(t(6540),t(5680));const o={},i="RAND",l={unversionedId:"sql-syntax/functions/math/rand",id:"sql-syntax/functions/math/rand",title:"RAND",description:"The RAND function is used to generate a random float value between 0 (inclusive) and 1 (exclusive). The function takes an optional seed value, which must be of the FLOAT type. If a seed value is provided, the random number generator will be initialized with that seed, producing a deterministic sequence of random numbers.",source:"@site/docs/sql-syntax/functions/math/rand.md",sourceDirName:"sql-syntax/functions/math",slug:"/sql-syntax/functions/math/rand",permalink:"/docs/0.16.0/sql-syntax/functions/math/rand",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"RADIANS",permalink:"/docs/0.16.0/sql-syntax/functions/math/radians"},next:{title:"ROUND",permalink:"/docs/0.16.0/sql-syntax/functions/math/round"}},s={},u=[{value:"Syntax",id:"syntax",level:2},{value:"Examples",id:"examples",level:2},{value:"Error Cases",id:"error-cases",level:2}],c={toc:u},p="wrapper";function d(e){let{components:n,...t}=e;return(0,a.yg)(p,(0,r.A)({},c,t,{components:n,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"rand"},"RAND"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"RAND")," function is used to generate a random float value between 0 (inclusive) and 1 (exclusive). The function takes an optional seed value, which must be of the FLOAT type. If a seed value is provided, the random number generator will be initialized with that seed, producing a deterministic sequence of random numbers."),(0,a.yg)("h2",{id:"syntax"},"Syntax"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"RAND([seed])\n")),(0,a.yg)("h2",{id:"examples"},"Examples"),(0,a.yg)("ol",null,(0,a.yg)("li",{parentName:"ol"},"Using the ",(0,a.yg)("inlineCode",{parentName:"li"},"RAND")," function without a seed:")),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT RAND() AS rand;\n-- Result: A random float between 0 and 1\n")),(0,a.yg)("ol",{start:2},(0,a.yg)("li",{parentName:"ol"},"Using the ",(0,a.yg)("inlineCode",{parentName:"li"},"RAND")," function with a seed:")),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT RAND(123) AS rand1, RAND(789.0) AS rand2;\n-- Result: 0.17325464426155657, 0.9635218234007941\n")),(0,a.yg)("ol",{start:3},(0,a.yg)("li",{parentName:"ol"},"Using the ",(0,a.yg)("inlineCode",{parentName:"li"},"RAND")," function with NULL:")),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT RAND(NULL) AS rand;\n-- Result: NULL\n")),(0,a.yg)("h2",{id:"error-cases"},"Error Cases"),(0,a.yg)("ol",null,(0,a.yg)("li",{parentName:"ol"},"The ",(0,a.yg)("inlineCode",{parentName:"li"},"RAND")," function requires the argument to be of FLOAT type, if provided:")),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},'SELECT RAND(\'string\') AS rand;\n-- Error: FunctionRequiresFloatValue("RAND")\n\nSELECT RAND(TRUE) AS rand;\n-- Error: FunctionRequiresFloatValue("RAND")\n\nSELECT RAND(FALSE) AS rand;\n-- Error: FunctionRequiresFloatValue("RAND")\n')),(0,a.yg)("ol",{start:2},(0,a.yg)("li",{parentName:"ol"},"The ",(0,a.yg)("inlineCode",{parentName:"li"},"RAND")," function takes at most one argument:")),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT RAND('string', 'string2') AS rand;\n-- Error: FunctionArgsLengthNotWithinRange(\"RAND\", 0, 1, 2)\n")))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/3961e600.447d8182.js b/docs/0.16.0/assets/js/3961e600.447d8182.js new file mode 100644 index 00000000..6c14165a --- /dev/null +++ b/docs/0.16.0/assets/js/3961e600.447d8182.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[9565],{5680:(e,n,a)=>{a.d(n,{xA:()=>p,yg:()=>d});var t=a(6540);function l(e,n,a){return n in e?Object.defineProperty(e,n,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[n]=a,e}function r(e,n){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var t=Object.getOwnPropertySymbols(e);n&&(t=t.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),a.push.apply(a,t)}return a}function i(e){for(var n=1;n=0||(l[a]=e[a]);return l}(e,n);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(t=0;t=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(l[a]=e[a])}return l}var g=t.createContext({}),s=function(e){var n=t.useContext(g),a=n;return e&&(a="function"==typeof e?e(n):i(i({},n),e)),a},p=function(e){var n=s(e.components);return t.createElement(g.Provider,{value:n},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var n=e.children;return t.createElement(t.Fragment,{},n)}},c=t.forwardRef((function(e,n){var a=e.components,l=e.mdxType,r=e.originalType,g=e.parentName,p=o(e,["components","mdxType","originalType","parentName"]),u=s(a),c=l,d=u["".concat(g,".").concat(c)]||u[c]||m[c]||r;return a?t.createElement(d,i(i({ref:n},p),{},{components:a})):t.createElement(d,i({ref:n},p))}));function d(e,n){var a=arguments,l=n&&n.mdxType;if("string"==typeof e||l){var r=a.length,i=new Array(r);i[0]=c;var o={};for(var g in n)hasOwnProperty.call(n,g)&&(o[g]=n[g]);o.originalType=e,o[u]="string"==typeof e?e:l,i[1]=o;for(var s=2;s{a.r(n),a.d(n,{assets:()=>g,contentTitle:()=>i,default:()=>m,frontMatter:()=>r,metadata:()=>o,toc:()=>s});var t=a(8168),l=(a(6540),a(5680));const r={},i="JSON Storage",o={unversionedId:"storages/supported-storages/json-storage",id:"storages/supported-storages/json-storage",title:"JSON Storage",description:"Introduction",source:"@site/docs/storages/supported-storages/json-storage.md",sourceDirName:"storages/supported-storages",slug:"/storages/supported-storages/json-storage",permalink:"/docs/0.16.0/storages/supported-storages/json-storage",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"IndexedDB Storage",permalink:"/docs/0.16.0/storages/supported-storages/idb-storage"},next:{title:"Memory Storage",permalink:"/docs/0.16.0/storages/supported-storages/memory-storage"}},g={},s=[{value:"Introduction",id:"introduction",level:2},{value:"Structure",id:"structure",level:2},{value:"Schema File",id:"schema-file",level:2},{value:"Schemaless Table",id:"schemaless-table",level:3},{value:"Data File",id:"data-file",level:2},{value:"*.jsonl File Format",id:"jsonl-file-format",level:3},{value:"*.json File Format",id:"json-file-format",level:3},{value:"Examples",id:"examples",level:2},{value:"Read Existing JSON/JSONL Schemaless Files",id:"read-existing-jsonjsonl-schemaless-files",level:3},{value:"Create Schema Table",id:"create-schema-table",level:3},{value:"Limitation",id:"limitation",level:2}],p={toc:s},u="wrapper";function m(e){let{components:n,...a}=e;return(0,l.yg)(u,(0,t.A)({},p,a,{components:n,mdxType:"MDXLayout"}),(0,l.yg)("h1",{id:"json-storage"},"JSON Storage"),(0,l.yg)("h2",{id:"introduction"},"Introduction"),(0,l.yg)("p",null,"The JSON Storage system is comprised of two types of files: ",(0,l.yg)("a",{parentName:"p",href:"#schema-file"},"Schema file"),"(optional) and ",(0,l.yg)("a",{parentName:"p",href:"#data-file"},"Data file"),". The Schema file is written in Standard SQL and is responsible for storing the structure of the table. The Data file contains the actual data and supports two file formats: ",(0,l.yg)("inlineCode",{parentName:"p"},"*.json")," and ",(0,l.yg)("inlineCode",{parentName:"p"},"*.jsonl"),". This document provides detailed ",(0,l.yg)("a",{parentName:"p",href:"#examples"},"examples")," of how to create schema and read/write data using the Json Storage system. While it supports all DML features, it is particularly specialized for ",(0,l.yg)("inlineCode",{parentName:"p"},"SELECT")," and ",(0,l.yg)("inlineCode",{parentName:"p"},"APPEND INSERT"),". For further information, please refer to the ",(0,l.yg)("a",{parentName:"p",href:"#limitation"},"Limitations")," section."),(0,l.yg)("h2",{id:"structure"},"Structure"),(0,l.yg)("p",null,"JSON Storage is based on two types of files: ",(0,l.yg)("inlineCode",{parentName:"p"},"Schema")," and ",(0,l.yg)("inlineCode",{parentName:"p"},"Data"),". The ",(0,l.yg)("inlineCode",{parentName:"p"},"Schema")," file contains the definition of the structure of the data, while the ",(0,l.yg)("inlineCode",{parentName:"p"},"Data")," file contains the actual data."),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"gluesql> CREATE TABLE User (\n id INT,\n name TEXT\n)\n")),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sh"},"$ ls -l\n\nUser.sql # Schema file\nUser.jsonl # Data file\n")),(0,l.yg)("h2",{id:"schema-file"},"Schema File"),(0,l.yg)("p",null,"The schema definition is saved in a file named ",(0,l.yg)("inlineCode",{parentName:"p"},"{TABLE_NAME}.sql")," using standard SQL. For example, if the table name is ",(0,l.yg)("inlineCode",{parentName:"p"},"User"),", then the schema file will be named ",(0,l.yg)("inlineCode",{parentName:"p"},"User.sql"),"."),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"--! User.sql\nCREATE TABLE User (\n id INT,\n name TEXT,\n);\n")),(0,l.yg)("h3",{id:"schemaless-table"},"Schemaless Table"),(0,l.yg)("p",null,"A schemaless table is optional, and if there is no corresponding ",(0,l.yg)("inlineCode",{parentName:"p"},"{TABLE_NAME}.sql")," file, the table is schemaless. A schemaless table can save any data regardless of column name and data type."),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"gluesql> CREATE Table User;\n")),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sh"},"$ ls -l\n\nUser.jsonl\n")),(0,l.yg)("h2",{id:"data-file"},"Data File"),(0,l.yg)("p",null,"JSON Storage saves data in two types of data files: ",(0,l.yg)("inlineCode",{parentName:"p"},"*.jsonl")," (default) and ",(0,l.yg)("inlineCode",{parentName:"p"},"*.json"),"."),(0,l.yg)("h3",{id:"jsonl-file-format"},(0,l.yg)("inlineCode",{parentName:"h3"},"*.jsonl")," File Format"),(0,l.yg)("p",null,"The ",(0,l.yg)("inlineCode",{parentName:"p"},"*.jsonl")," file format is a file containing one JSON object per line. For example:"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-json"},'{"id": 1, "name": "Glue"}\n{"id": 2, "name": "SQL"}\n')),(0,l.yg)("h3",{id:"json-file-format"},(0,l.yg)("inlineCode",{parentName:"h3"},"*.json")," File Format"),(0,l.yg)("p",null,"The ",(0,l.yg)("inlineCode",{parentName:"p"},"*.json")," file format supports two different formats:"),(0,l.yg)("ol",null,(0,l.yg)("li",{parentName:"ol"},"Array of JSON")),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-json"},'[\n {\n "id": 1,\n "name": "Glue"\n },\n {\n "id": 2,\n "name": "SQL"\n }\n]\n')),(0,l.yg)("ol",{start:2},(0,l.yg)("li",{parentName:"ol"},"Single JSON")),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-json"},'{\n "name": "GlueSQL"\n "keywords": ["Database, Rust"]\n "stars": 999999\n}\n')),(0,l.yg)("h2",{id:"examples"},"Examples"),(0,l.yg)("h3",{id:"read-existing-jsonjsonl-schemaless-files"},"Read Existing JSON/JSONL Schemaless Files"),(0,l.yg)("ol",null,(0,l.yg)("li",{parentName:"ol"},"Locate your JSON/JSONL schemaless files in the data path. Here, we use ",(0,l.yg)("inlineCode",{parentName:"li"},"./data"),".")),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre"},"$ ls -rlt ./data\n\nUser.json\nLoginHistory.jsonl\n")),(0,l.yg)("p",null,"Keep in mind that if there are no ",(0,l.yg)("inlineCode",{parentName:"p"},"*.sql")," files, the data is considered schemaless, meaning that the number of columns in each row may vary."),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-json"},'//! User.json\n[\n {\n "id": 1,\n "name": "Alice",\n "location": "New York"\n },\n {\n "id": 2,\n "name": "Bob",\n "language": "Rust"\n },\n {\n "id": 3,\n "name": "Eve"\n }\n]\n')),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-json"},'//! LoginHistory.jsonl\n{"timestamp": "2023-05-01T14:36:22.000Z", "userId": 1, "action": "login"}\n{"timestamp": "2023-05-01T14:38:17.000Z", "userId": 2, "action": "logout"}\n{"timestamp": "2023-05-02T08:12:05.000Z", "userId": 2, "action": "logout"}\n{"timestamp": "2023-05-02T09:45:13.000Z", "userId": 3, "action": "login"}\n{"timestamp": "2023-05-03T16:21:44.000Z", "userId": 1, "action": "logout"}\n')),(0,l.yg)("ol",{start:2},(0,l.yg)("li",{parentName:"ol"},"Read with GlueSQL JSON Storage")),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-rust"},'let path = "./data/";\nlet json_storage = JsonStorage::new(path).unwrap();\nlet mut glue = Glue::new(json_storage);\n\nglue.execute("\nSELECT *\nFROM User U\nJOIN LoginHistory L ON U.id = L.userId;\n");\n')),(0,l.yg)("table",null,(0,l.yg)("thead",{parentName:"table"},(0,l.yg)("tr",{parentName:"thead"},(0,l.yg)("th",{parentName:"tr",align:null},"action"),(0,l.yg)("th",{parentName:"tr",align:null},"id"),(0,l.yg)("th",{parentName:"tr",align:null},"language"),(0,l.yg)("th",{parentName:"tr",align:null},"location"),(0,l.yg)("th",{parentName:"tr",align:null},"name"),(0,l.yg)("th",{parentName:"tr",align:null},"timestamp"),(0,l.yg)("th",{parentName:"tr",align:null},"userId"))),(0,l.yg)("tbody",{parentName:"table"},(0,l.yg)("tr",{parentName:"tbody"},(0,l.yg)("td",{parentName:"tr",align:null},"login"),(0,l.yg)("td",{parentName:"tr",align:null},"1"),(0,l.yg)("td",{parentName:"tr",align:null}),(0,l.yg)("td",{parentName:"tr",align:null},"New York"),(0,l.yg)("td",{parentName:"tr",align:null},"Alice"),(0,l.yg)("td",{parentName:"tr",align:null},"2023-05-01T14:36:22.000Z"),(0,l.yg)("td",{parentName:"tr",align:null},"1")),(0,l.yg)("tr",{parentName:"tbody"},(0,l.yg)("td",{parentName:"tr",align:null},"logout"),(0,l.yg)("td",{parentName:"tr",align:null},"1"),(0,l.yg)("td",{parentName:"tr",align:null}),(0,l.yg)("td",{parentName:"tr",align:null},"New York"),(0,l.yg)("td",{parentName:"tr",align:null},"Alice"),(0,l.yg)("td",{parentName:"tr",align:null},"2023-05-03T16:21:44.000Z"),(0,l.yg)("td",{parentName:"tr",align:null},"1")),(0,l.yg)("tr",{parentName:"tbody"},(0,l.yg)("td",{parentName:"tr",align:null},"logout"),(0,l.yg)("td",{parentName:"tr",align:null},"2"),(0,l.yg)("td",{parentName:"tr",align:null},"Rust"),(0,l.yg)("td",{parentName:"tr",align:null}),(0,l.yg)("td",{parentName:"tr",align:null},"Bob"),(0,l.yg)("td",{parentName:"tr",align:null},"2023-05-01T14:38:17.000Z"),(0,l.yg)("td",{parentName:"tr",align:null},"2")),(0,l.yg)("tr",{parentName:"tbody"},(0,l.yg)("td",{parentName:"tr",align:null},"logout"),(0,l.yg)("td",{parentName:"tr",align:null},"2"),(0,l.yg)("td",{parentName:"tr",align:null},"Rust"),(0,l.yg)("td",{parentName:"tr",align:null}),(0,l.yg)("td",{parentName:"tr",align:null},"Bob"),(0,l.yg)("td",{parentName:"tr",align:null},"2023-05-02T08:12:05.000Z"),(0,l.yg)("td",{parentName:"tr",align:null},"2")),(0,l.yg)("tr",{parentName:"tbody"},(0,l.yg)("td",{parentName:"tr",align:null},"login"),(0,l.yg)("td",{parentName:"tr",align:null},"3"),(0,l.yg)("td",{parentName:"tr",align:null}),(0,l.yg)("td",{parentName:"tr",align:null}),(0,l.yg)("td",{parentName:"tr",align:null},"Eve"),(0,l.yg)("td",{parentName:"tr",align:null},"2023-05-02T09:45:13.000Z"),(0,l.yg)("td",{parentName:"tr",align:null},"3")))),(0,l.yg)("h3",{id:"create-schema-table"},"Create Schema Table"),(0,l.yg)("ol",null,(0,l.yg)("li",{parentName:"ol"},"Create Table")),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-rust"},'let path = "./data/";\nlet json_storage = JsonStorage::new(path).unwrap();\nlet mut glue = Glue::new(json_storage);\n\nglue.execute("\nCREATE TABLE Account (\n accountId INT NOT NULL,\n accountOwner TEXT NOT NULL,\n accountType TEXT NOT NULL,\n balance INT NOT NULL,\n isActive BOOLEAN NOT NULL\n);\n");\n')),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sh"},"$ ls -l\n\nAccount.sql\nAccount.jsonl\n")),(0,l.yg)("ol",{start:2},(0,l.yg)("li",{parentName:"ol"},"Verity Schema file")),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"--! Account.sql\nCREATE TABLE Account (\n accountId INT NOT NULL,\n accountOwner TEXT NOT NULL,\n accountType TEXT NOT NULL,\n balance INT NOT NULL,\n isActive BOOLEAN NOT NULL\n);\n")),(0,l.yg)("ol",{start:3},(0,l.yg)("li",{parentName:"ol"},"Insert data")),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-rust"},"glue.execute(\"\nINSERT INTO Account VALUES\n (10001, 'John Smith', 'Checking', 5000, true),\n (10002, 'Jane Doe', 'Savings', 10000, true),\n (10003, 'Robert Johnson', 'Checking', 2500, false),\n (10004, 'Alice Kim', 'Savings', 7500, true),\n (10005, 'Michael Chen', 'Checking', 10000, true);\n\");\n")),(0,l.yg)("ol",{start:4},(0,l.yg)("li",{parentName:"ol"},"Select data")),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-rust"},'glue.execute("SELECT * FROM Account;");\n')),(0,l.yg)("table",null,(0,l.yg)("thead",{parentName:"table"},(0,l.yg)("tr",{parentName:"thead"},(0,l.yg)("th",{parentName:"tr",align:null},"accountId"),(0,l.yg)("th",{parentName:"tr",align:null},"accountOwner"),(0,l.yg)("th",{parentName:"tr",align:null},"accountType"),(0,l.yg)("th",{parentName:"tr",align:null},"balance"),(0,l.yg)("th",{parentName:"tr",align:null},"isActive"))),(0,l.yg)("tbody",{parentName:"table"},(0,l.yg)("tr",{parentName:"tbody"},(0,l.yg)("td",{parentName:"tr",align:null},"10001"),(0,l.yg)("td",{parentName:"tr",align:null},"John Smith"),(0,l.yg)("td",{parentName:"tr",align:null},"Checking"),(0,l.yg)("td",{parentName:"tr",align:null},"5000"),(0,l.yg)("td",{parentName:"tr",align:null},"TRUE")),(0,l.yg)("tr",{parentName:"tbody"},(0,l.yg)("td",{parentName:"tr",align:null},"10002"),(0,l.yg)("td",{parentName:"tr",align:null},"Jane Doe"),(0,l.yg)("td",{parentName:"tr",align:null},"Savings"),(0,l.yg)("td",{parentName:"tr",align:null},"10000"),(0,l.yg)("td",{parentName:"tr",align:null},"TRUE")),(0,l.yg)("tr",{parentName:"tbody"},(0,l.yg)("td",{parentName:"tr",align:null},"10003"),(0,l.yg)("td",{parentName:"tr",align:null},"Robert Johnson"),(0,l.yg)("td",{parentName:"tr",align:null},"Checking"),(0,l.yg)("td",{parentName:"tr",align:null},"2500"),(0,l.yg)("td",{parentName:"tr",align:null},"FALSE")),(0,l.yg)("tr",{parentName:"tbody"},(0,l.yg)("td",{parentName:"tr",align:null},"10004"),(0,l.yg)("td",{parentName:"tr",align:null},"Alice Kim"),(0,l.yg)("td",{parentName:"tr",align:null},"Savings"),(0,l.yg)("td",{parentName:"tr",align:null},"7500"),(0,l.yg)("td",{parentName:"tr",align:null},"TRUE")),(0,l.yg)("tr",{parentName:"tbody"},(0,l.yg)("td",{parentName:"tr",align:null},"10005"),(0,l.yg)("td",{parentName:"tr",align:null},"Michael Chen"),(0,l.yg)("td",{parentName:"tr",align:null},"Checking"),(0,l.yg)("td",{parentName:"tr",align:null},"10000"),(0,l.yg)("td",{parentName:"tr",align:null},"TRUE")))),(0,l.yg)("ol",{start:5},(0,l.yg)("li",{parentName:"ol"},"Verify Data file")),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-json"},'//! Account.jsonl\n{"accountId":10001,"accountOwner":"John Smith","accountType":"Checking","balance":5000,"isActive":true}\n{"accountId":10002,"accountOwner":"Jane Doe","accountType":"Savings","balance":10000,"isActive":true}\n{"accountId":10003,"accountOwner":"Robert Johnson","accountType":"Checking","balance":2500,"isActive":false}\n{"accountId":10004,"accountOwner":"Alice Kim","accountType":"Savings","balance":7500,"isActive":true}\n{"accountId":10005,"accountOwner":"Michael Chen","accountType":"Checking","balance":10000,"isActive":true}\n')),(0,l.yg)("h2",{id:"limitation"},"Limitation"),(0,l.yg)("p",null,"JSON Storage is capable of supporting a variety of operations, including ",(0,l.yg)("inlineCode",{parentName:"p"},"SELECT"),", ",(0,l.yg)("inlineCode",{parentName:"p"},"INSERT"),", ",(0,l.yg)("inlineCode",{parentName:"p"},"DELETE"),", and ",(0,l.yg)("inlineCode",{parentName:"p"},"UPDATE"),".",(0,l.yg)("br",{parentName:"p"}),"\n","However, its design primarily emphasizes ",(0,l.yg)("inlineCode",{parentName:"p"},"SELECT")," and ",(0,l.yg)("inlineCode",{parentName:"p"},"APPEND INSERT")," functionality.",(0,l.yg)("br",{parentName:"p"}),"\n","It's important to note that if you perform ",(0,l.yg)("inlineCode",{parentName:"p"},"DELETE"),", ",(0,l.yg)("inlineCode",{parentName:"p"},"UPDATE"),", or ",(0,l.yg)("inlineCode",{parentName:"p"},"INSERT in the middle of the rows"),", it can cause the internal rewriting of all the rows, which can lead to a decrease in performance."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/3cfbc8af.042652b0.js b/docs/0.16.0/assets/js/3cfbc8af.042652b0.js new file mode 100644 index 00000000..c4b6dd57 --- /dev/null +++ b/docs/0.16.0/assets/js/3cfbc8af.042652b0.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[7433],{5680:(e,t,n)=>{n.d(t,{xA:()=>s,yg:()=>y});var r=n(6540);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function c(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var o=r.createContext({}),u=function(e){var t=r.useContext(o),n=t;return e&&(n="function"==typeof e?e(t):c(c({},t),e)),n},s=function(e){var t=u(e.components);return r.createElement(o.Provider,{value:t},e.children)},p="mdxType",g={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,l=e.originalType,o=e.parentName,s=i(e,["components","mdxType","originalType","parentName"]),p=u(n),d=a,y=p["".concat(o,".").concat(d)]||p[d]||g[d]||l;return n?r.createElement(y,c(c({ref:t},s),{},{components:n})):r.createElement(y,c({ref:t},s))}));function y(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var l=n.length,c=new Array(l);c[0]=d;var i={};for(var o in t)hasOwnProperty.call(t,o)&&(i[o]=t[o]);i.originalType=e,i[p]="string"==typeof e?e:a,c[1]=i;for(var u=2;u{n.r(t),n.d(t,{assets:()=>o,contentTitle:()=>c,default:()=>g,frontMatter:()=>l,metadata:()=>i,toc:()=>u});var r=n(8168),a=(n(6540),n(5680));const l={},c="Character Conversion",i={unversionedId:"ast-builder/functions/text/character-conversion",id:"ast-builder/functions/text/character-conversion",title:"Character Conversion",description:"The AST Builder API in GlueSQL allows you to execute ascii and chr functions for character conversion.",source:"@site/docs/ast-builder/functions/text/character-conversion.md",sourceDirName:"ast-builder/functions/text",slug:"/ast-builder/functions/text/character-conversion",permalink:"/docs/0.16.0/ast-builder/functions/text/character-conversion",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"Case Conversion",permalink:"/docs/0.16.0/ast-builder/functions/text/case-conversion"},next:{title:"Padding",permalink:"/docs/0.16.0/ast-builder/functions/text/padding"}},o={},u=[{value:"ascii",id:"ascii",level:2},{value:"chr",id:"chr",level:2},{value:"Examples",id:"examples",level:2}],s={toc:u},p="wrapper";function g(e){let{components:t,...n}=e;return(0,a.yg)(p,(0,r.A)({},s,n,{components:t,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"character-conversion"},"Character Conversion"),(0,a.yg)("p",null,"The AST Builder API in GlueSQL allows you to execute ",(0,a.yg)("inlineCode",{parentName:"p"},"ascii")," and ",(0,a.yg)("inlineCode",{parentName:"p"},"chr")," functions for character conversion."),(0,a.yg)("h2",{id:"ascii"},"ascii"),(0,a.yg)("p",null,(0,a.yg)("inlineCode",{parentName:"p"},"ascii")," returns the ASCII value for the specific character."),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-rust"},"ascii<'a, T: Into>>(expr: T) -> ExprNode<'a>\n")),(0,a.yg)("h2",{id:"chr"},"chr"),(0,a.yg)("p",null,(0,a.yg)("inlineCode",{parentName:"p"},"chr")," returns the character based on the ASCII code."),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-rust"},"chr<'a, T: Into>>(expr: T) -> ExprNode<'a>\n")),(0,a.yg)("h2",{id:"examples"},"Examples"),(0,a.yg)("p",null,"In these examples, the ASCII and CHR functions should return matching values."),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-rust"},'use {\n gluesql_core::{ast_builder::{function as f, *}}\n};\n\nvalues(vec![\n vec![f::ascii("\'\\t\'"), f::chr(9)],\n vec![f::ascii("\'\\n\'"), f::chr(10)],\n vec![f::ascii("\'\\r\'"), f::chr(13)],\n vec![f::ascii("\' \'"), f::chr(32)],\n vec![f::ascii("\'!\'"), f::chr(33)],\n vec![f::ascii("\'\\"\'"), f::chr(34)],\n vec![f::ascii("\'#\'"), f::chr(35)],\n vec![f::ascii("\'$\'"), f::chr(36)],\n vec![f::ascii("\'%\'"), f::chr(37)],\n vec![f::ascii("\'&\'"), f::chr(38)],\n vec![f::ascii("\'\'\'\'"), f::chr(39)],\n vec![f::ascii("\',\'"), f::chr(44)],\n])\n.alias_as("Sub")\n.select()\n.project("column1 AS ascii")\n.project("column2 AS char")\n.execute(glue)\n.await;\n')),(0,a.yg)("table",null,(0,a.yg)("thead",{parentName:"table"},(0,a.yg)("tr",{parentName:"thead"},(0,a.yg)("th",{parentName:"tr",align:null},"ascii"),(0,a.yg)("th",{parentName:"tr",align:null},"char"))),(0,a.yg)("tbody",{parentName:"table"},(0,a.yg)("tr",{parentName:"tbody"},(0,a.yg)("td",{parentName:"tr",align:null},"9"),(0,a.yg)("td",{parentName:"tr",align:null},"\\t")),(0,a.yg)("tr",{parentName:"tbody"},(0,a.yg)("td",{parentName:"tr",align:null},"10"),(0,a.yg)("td",{parentName:"tr",align:null},"\\n")),(0,a.yg)("tr",{parentName:"tbody"},(0,a.yg)("td",{parentName:"tr",align:null},"13"),(0,a.yg)("td",{parentName:"tr",align:null},"\\r")),(0,a.yg)("tr",{parentName:"tbody"},(0,a.yg)("td",{parentName:"tr",align:null},"32"),(0,a.yg)("td",{parentName:"tr",align:null},'" "')),(0,a.yg)("tr",{parentName:"tbody"},(0,a.yg)("td",{parentName:"tr",align:null},"33"),(0,a.yg)("td",{parentName:"tr",align:null},"!")),(0,a.yg)("tr",{parentName:"tbody"},(0,a.yg)("td",{parentName:"tr",align:null},"34"),(0,a.yg)("td",{parentName:"tr",align:null},'"')),(0,a.yg)("tr",{parentName:"tbody"},(0,a.yg)("td",{parentName:"tr",align:null},"35"),(0,a.yg)("td",{parentName:"tr",align:null},"#")),(0,a.yg)("tr",{parentName:"tbody"},(0,a.yg)("td",{parentName:"tr",align:null},"36"),(0,a.yg)("td",{parentName:"tr",align:null},"$")),(0,a.yg)("tr",{parentName:"tbody"},(0,a.yg)("td",{parentName:"tr",align:null},"37"),(0,a.yg)("td",{parentName:"tr",align:null},"%")),(0,a.yg)("tr",{parentName:"tbody"},(0,a.yg)("td",{parentName:"tr",align:null},"38"),(0,a.yg)("td",{parentName:"tr",align:null},"&")),(0,a.yg)("tr",{parentName:"tbody"},(0,a.yg)("td",{parentName:"tr",align:null},"39"),(0,a.yg)("td",{parentName:"tr",align:null},"'")),(0,a.yg)("tr",{parentName:"tbody"},(0,a.yg)("td",{parentName:"tr",align:null},"44"),(0,a.yg)("td",{parentName:"tr",align:null},",")))))}g.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/3ee3a370.68b8d0ad.js b/docs/0.16.0/assets/js/3ee3a370.68b8d0ad.js new file mode 100644 index 00000000..df84a8fb --- /dev/null +++ b/docs/0.16.0/assets/js/3ee3a370.68b8d0ad.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[5010],{3750:s=>{s.exports=JSON.parse('{"label":"TDD","permalink":"/docs/0.16.0/blog/tags/tdd","allTagsPath":"/docs/0.16.0/blog/tags","count":1}')}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/402da695.dca958f2.js b/docs/0.16.0/assets/js/402da695.dca958f2.js new file mode 100644 index 00000000..819ec8d2 --- /dev/null +++ b/docs/0.16.0/assets/js/402da695.dca958f2.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[770],{5680:(e,t,a)=>{a.d(t,{xA:()=>m,yg:()=>y});var n=a(6540);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function o(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function l(e){for(var t=1;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var s=n.createContext({}),p=function(e){var t=n.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):l(l({},t),e)),a},m=function(e){var t=p(e.components);return n.createElement(s.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},c=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,o=e.originalType,s=e.parentName,m=i(e,["components","mdxType","originalType","parentName"]),d=p(a),c=r,y=d["".concat(s,".").concat(c)]||d[c]||u[c]||o;return a?n.createElement(y,l(l({ref:t},m),{},{components:a})):n.createElement(y,l({ref:t},m))}));function y(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=a.length,l=new Array(o);l[0]=c;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i[d]="string"==typeof e?e:r,l[1]=i;for(var p=2;p{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>u,frontMatter:()=>o,metadata:()=>i,toc:()=>p});var n=a(8168),r=(a(6540),a(5680));const o={sidebar_position:2},l="DROP TABLE",i={unversionedId:"sql-syntax/statements/data-definition/drop-table",id:"sql-syntax/statements/data-definition/drop-table",title:"DROP TABLE",description:"The DROP TABLE statement is an SQL command used to remove one or more tables from a database. This operation is useful when you no longer need a table or want to clear out old data structures. In this document, we'll explain the syntax and usage of the DROP TABLE statement, including the IF EXISTS clause and dropping multiple tables at once.",source:"@site/docs/sql-syntax/statements/data-definition/drop-table.md",sourceDirName:"sql-syntax/statements/data-definition",slug:"/sql-syntax/statements/data-definition/drop-table",permalink:"/docs/0.16.0/sql-syntax/statements/data-definition/drop-table",draft:!1,tags:[],version:"current",sidebarPosition:2,frontMatter:{sidebar_position:2},sidebar:"autoSidebar",previous:{title:"CREATE TABLE",permalink:"/docs/0.16.0/sql-syntax/statements/data-definition/create-table"},next:{title:"CREATE INDEX",permalink:"/docs/0.16.0/sql-syntax/statements/data-definition/create-index"}},s={},p=[{value:"Syntax",id:"syntax",level:2},{value:"Examples",id:"examples",level:2},{value:"Warning",id:"warning",level:2},{value:"Summary",id:"summary",level:2}],m={toc:p},d="wrapper";function u(e){let{components:t,...a}=e;return(0,r.yg)(d,(0,n.A)({},m,a,{components:t,mdxType:"MDXLayout"}),(0,r.yg)("h1",{id:"drop-table"},"DROP TABLE"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"DROP TABLE")," statement is an SQL command used to remove one or more tables from a database. This operation is useful when you no longer need a table or want to clear out old data structures. In this document, we'll explain the syntax and usage of the ",(0,r.yg)("inlineCode",{parentName:"p"},"DROP TABLE")," statement, including the ",(0,r.yg)("inlineCode",{parentName:"p"},"IF EXISTS")," clause and dropping multiple tables at once."),(0,r.yg)("h2",{id:"syntax"},"Syntax"),(0,r.yg)("p",null,"The basic syntax for the ",(0,r.yg)("inlineCode",{parentName:"p"},"DROP TABLE")," statement is as follows:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"DROP TABLE [IF EXISTS] table_name [, table_name2, ...];\n")),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"IF EXISTS"),": This optional clause allows you to check if a table exists in the database before attempting to drop it. If the table does not exist, the command does nothing; otherwise, it drops the specified table."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"table_name"),": The name of the table you want to drop. You can also drop multiple tables by separating their names with commas.")),(0,r.yg)("h2",{id:"examples"},"Examples"),(0,r.yg)("ol",null,(0,r.yg)("li",{parentName:"ol"},"Dropping a single table:")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"DROP TABLE employees;\n")),(0,r.yg)("p",null,"This command will drop the ",(0,r.yg)("inlineCode",{parentName:"p"},"employees")," table from the database."),(0,r.yg)("ol",{start:2},(0,r.yg)("li",{parentName:"ol"},"Dropping a table using the ",(0,r.yg)("inlineCode",{parentName:"li"},"IF EXISTS")," clause:")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"DROP TABLE IF EXISTS employees;\n")),(0,r.yg)("p",null,"This command will drop the ",(0,r.yg)("inlineCode",{parentName:"p"},"employees")," table if it exists in the database. If the table does not exist, the command does nothing."),(0,r.yg)("ol",{start:3},(0,r.yg)("li",{parentName:"ol"},"Dropping multiple tables at once:")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"DROP TABLE employees, table_name;\n")),(0,r.yg)("p",null,"This command will drop both the ",(0,r.yg)("inlineCode",{parentName:"p"},"employees")," and ",(0,r.yg)("inlineCode",{parentName:"p"},"table_name")," tables from the database."),(0,r.yg)("h2",{id:"warning"},"Warning"),(0,r.yg)("p",null,"When using the ",(0,r.yg)("inlineCode",{parentName:"p"},"DROP TABLE")," statement, be cautious, as this operation will permanently remove the table and all its data from the database. Always make sure to backup your data before performing this operation."),(0,r.yg)("h2",{id:"summary"},"Summary"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"DROP TABLE")," statement is an essential SQL command that allows you to remove tables from a database. It supports an optional ",(0,r.yg)("inlineCode",{parentName:"p"},"IF EXISTS")," clause to prevent errors if a table does not exist, and you can drop multiple tables at once by separating their names with commas. By understanding the ",(0,r.yg)("inlineCode",{parentName:"p"},"DROP TABLE")," syntax, you can efficiently manage your database schema and remove unnecessary tables when needed."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/41718851.37d8e0c9.js b/docs/0.16.0/assets/js/41718851.37d8e0c9.js new file mode 100644 index 00000000..baac7d08 --- /dev/null +++ b/docs/0.16.0/assets/js/41718851.37d8e0c9.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[7096],{5680:(e,n,t)=>{t.d(n,{xA:()=>c,yg:()=>y});var a=t(6540);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function l(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function i(e){for(var n=1;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var s=a.createContext({}),p=function(e){var n=a.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},c=function(e){var n=p(e.components);return a.createElement(s.Provider,{value:n},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},g=a.forwardRef((function(e,n){var t=e.components,r=e.mdxType,l=e.originalType,s=e.parentName,c=o(e,["components","mdxType","originalType","parentName"]),u=p(t),g=r,y=u["".concat(s,".").concat(g)]||u[g]||m[g]||l;return t?a.createElement(y,i(i({ref:n},c),{},{components:t})):a.createElement(y,i({ref:n},c))}));function y(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var l=t.length,i=new Array(l);i[0]=g;var o={};for(var s in n)hasOwnProperty.call(n,s)&&(o[s]=n[s]);o.originalType=e,o[u]="string"==typeof e?e:r,i[1]=o;for(var p=2;p{t.r(n),t.d(n,{assets:()=>s,contentTitle:()=>i,default:()=>m,frontMatter:()=>l,metadata:()=>o,toc:()=>p});var a=t(8168),r=(t(6540),t(5680));const l={},i="TRIM",o={unversionedId:"sql-syntax/functions/text/trim",id:"sql-syntax/functions/text/trim",title:"TRIM",description:"The TRIM function in SQL is used to remove leading, trailing, or both leading and trailing unwanted characters (often whitespace) from a string.",source:"@site/docs/sql-syntax/functions/text/trim.md",sourceDirName:"sql-syntax/functions/text",slug:"/sql-syntax/functions/text/trim",permalink:"/docs/0.16.0/sql-syntax/functions/text/trim",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"SUBSTR",permalink:"/docs/0.16.0/sql-syntax/functions/text/substr"},next:{title:"UPPER",permalink:"/docs/0.16.0/sql-syntax/functions/text/upper"}},s={},p=[{value:"Syntax",id:"syntax",level:2},{value:"Examples",id:"examples",level:2}],c={toc:p},u="wrapper";function m(e){let{components:n,...t}=e;return(0,r.yg)(u,(0,a.A)({},c,t,{components:n,mdxType:"MDXLayout"}),(0,r.yg)("h1",{id:"trim"},"TRIM"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"TRIM")," function in SQL is used to remove leading, trailing, or both leading and trailing unwanted characters (often whitespace) from a string."),(0,r.yg)("h2",{id:"syntax"},"Syntax"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"TRIM([LEADING | TRAILING | BOTH] [removal_string] FROM target_string)\n")),(0,r.yg)("p",null,"If ",(0,r.yg)("inlineCode",{parentName:"p"},"LEADING"),", ",(0,r.yg)("inlineCode",{parentName:"p"},"TRAILING"),", or ",(0,r.yg)("inlineCode",{parentName:"p"},"BOTH")," is not specified, ",(0,r.yg)("inlineCode",{parentName:"p"},"TRIM")," function will remove both leading and trailing spaces."),(0,r.yg)("h2",{id:"examples"},"Examples"),(0,r.yg)("p",null,"Here we are creating a table named ",(0,r.yg)("inlineCode",{parentName:"p"},"Item")," with a default value for the ",(0,r.yg)("inlineCode",{parentName:"p"},"name")," column. The default value is obtained by concatenating two strings. The first string is the result of trimming leading 'a' from 'aabc' and the second string is the result of trimming spaces from ' good '."),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE Item (\n name TEXT DEFAULT TRIM(LEADING 'a' FROM 'aabc') || TRIM(' good ')\n)\n")),(0,r.yg)("p",null,"We insert some data into the ",(0,r.yg)("inlineCode",{parentName:"p"},"Item")," table:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO Item VALUES\n (' Left blank'),\n ('Right blank '),\n (' Blank! '),\n ('Not Blank');\n")),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"TRIM")," function is used in a ",(0,r.yg)("inlineCode",{parentName:"p"},"SELECT")," statement to remove leading and trailing spaces from the ",(0,r.yg)("inlineCode",{parentName:"p"},"name")," column in the ",(0,r.yg)("inlineCode",{parentName:"p"},"Item")," table:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT TRIM(name) FROM Item;\n")),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"TRIM")," function can also be used with ",(0,r.yg)("inlineCode",{parentName:"p"},"NULL")," values. If the value is ",(0,r.yg)("inlineCode",{parentName:"p"},"NULL"),", the ",(0,r.yg)("inlineCode",{parentName:"p"},"TRIM")," function will return ",(0,r.yg)("inlineCode",{parentName:"p"},"NULL"),"."),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE NullName (name TEXT NULL);\nINSERT INTO NullName VALUES (NULL);\nSELECT TRIM(name) AS test FROM NullName;\n")),(0,r.yg)("p",null,"You can also specify a specific character to remove from the string. The following example removes 'xyz' from the string:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE Test (name TEXT);\nINSERT INTO Test VALUES\n (' blank '), \n ('xxxyzblankxyzxx'), \n ('xxxyzblank '),\n (' blankxyzxx'),\n (' xyzblankxyzxx'),\n ('xxxyzblankxyz ');\nSELECT TRIM(BOTH 'xyz' FROM name) FROM Test;\n")),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"LEADING")," and ",(0,r.yg)("inlineCode",{parentName:"p"},"TRAILING")," keywords can be used to remove characters from the beginning or the end of the string, respectively:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT TRIM(LEADING 'xyz' FROM name) FROM Test;\nSELECT TRIM(TRAILING 'xyz' FROM name) FROM Test;\n")),(0,r.yg)("p",null,"You can also nest ",(0,r.yg)("inlineCode",{parentName:"p"},"TRIM")," functions:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT TRIM(BOTH TRIM(BOTH ' potato ')) AS Case1;\n")),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"TRIM")," function requires string values. If you try to use it with a non-string value, an error will occur:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT TRIM('1' FROM 1) AS test FROM Test;\n")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/425cb3cb.214e68a0.js b/docs/0.16.0/assets/js/425cb3cb.214e68a0.js new file mode 100644 index 00000000..4d331f29 --- /dev/null +++ b/docs/0.16.0/assets/js/425cb3cb.214e68a0.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[8707],{5967:s=>{s.exports=JSON.parse('{"permalink":"/docs/0.16.0/blog/tags/gluesql","page":1,"postsPerPage":10,"totalPages":1,"totalCount":1,"blogDescription":"Blog","blogTitle":"Blog"}')}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/44954150.17b33b16.js b/docs/0.16.0/assets/js/44954150.17b33b16.js new file mode 100644 index 00000000..8a3fa9be --- /dev/null +++ b/docs/0.16.0/assets/js/44954150.17b33b16.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[2323],{5680:(e,r,t)=>{t.d(r,{xA:()=>l,yg:()=>b});var n=t(6540);function o(e,r,t){return r in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function a(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);r&&(n=n.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),t.push.apply(t,n)}return t}function s(e){for(var r=1;r=0||(o[t]=e[t]);return o}(e,r);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var p=n.createContext({}),c=function(e){var r=n.useContext(p),t=r;return e&&(t="function"==typeof e?e(r):s(s({},r),e)),t},l=function(e){var r=c(e.components);return n.createElement(p.Provider,{value:r},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var r=e.children;return n.createElement(n.Fragment,{},r)}},f=n.forwardRef((function(e,r){var t=e.components,o=e.mdxType,a=e.originalType,p=e.parentName,l=i(e,["components","mdxType","originalType","parentName"]),u=c(t),f=o,b=u["".concat(p,".").concat(f)]||u[f]||d[f]||a;return t?n.createElement(b,s(s({ref:r},l),{},{components:t})):n.createElement(b,s({ref:r},l))}));function b(e,r){var t=arguments,o=r&&r.mdxType;if("string"==typeof e||o){var a=t.length,s=new Array(a);s[0]=f;var i={};for(var p in r)hasOwnProperty.call(r,p)&&(i[p]=r[p]);i.originalType=e,i[u]="string"==typeof e?e:o,s[1]=i;for(var c=2;c{t.r(r),t.d(r,{assets:()=>p,contentTitle:()=>s,default:()=>d,frontMatter:()=>a,metadata:()=>i,toc:()=>c});var n=t(8168),o=(t(6540),t(5680));const a={},s="Operator Based",i={unversionedId:"ast-builder/expressions/operator-based",id:"ast-builder/expressions/operator-based",title:"Operator Based",description:"Todo",source:"@site/docs/ast-builder/expressions/operator-based.md",sourceDirName:"ast-builder/expressions",slug:"/ast-builder/expressions/operator-based",permalink:"/docs/0.16.0/ast-builder/expressions/operator-based",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"Nested",permalink:"/docs/0.16.0/ast-builder/expressions/nested"},next:{title:"Pattern Matching",permalink:"/docs/0.16.0/ast-builder/expressions/pattern-matching"}},p={},c=[{value:"Todo",id:"todo",level:2}],l={toc:c},u="wrapper";function d(e){let{components:r,...t}=e;return(0,o.yg)(u,(0,n.A)({},l,t,{components:r,mdxType:"MDXLayout"}),(0,o.yg)("h1",{id:"operator-based"},"Operator Based"),(0,o.yg)("h2",{id:"todo"},"Todo"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre"},"- BINARY_OP: Represents a binary operation (like +, -, *, /, etc.).\n- UNARY_OP: Represents a unary operation (like NOT, -, etc.).\n")))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/44f79c8d.0eabe5cf.js b/docs/0.16.0/assets/js/44f79c8d.0eabe5cf.js new file mode 100644 index 00000000..5abed9bd --- /dev/null +++ b/docs/0.16.0/assets/js/44f79c8d.0eabe5cf.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[550],{5680:(e,t,n)=>{n.d(t,{xA:()=>l,yg:()=>d});var o=n(6540);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function s(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function i(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var a=o.createContext({}),c=function(e){var t=o.useContext(a),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},l=function(e){var t=c(e.components);return o.createElement(a.Provider,{value:t},e.children)},m="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},f=o.forwardRef((function(e,t){var n=e.components,r=e.mdxType,s=e.originalType,a=e.parentName,l=u(e,["components","mdxType","originalType","parentName"]),m=c(n),f=r,d=m["".concat(a,".").concat(f)]||m[f]||p[f]||s;return n?o.createElement(d,i(i({ref:t},l),{},{components:n})):o.createElement(d,i({ref:t},l))}));function d(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var s=n.length,i=new Array(s);i[0]=f;var u={};for(var a in t)hasOwnProperty.call(t,a)&&(u[a]=t[a]);u.originalType=e,u[m]="string"==typeof e?e:r,i[1]=u;for(var c=2;c{n.r(t),n.d(t,{assets:()=>a,contentTitle:()=>i,default:()=>p,frontMatter:()=>s,metadata:()=>u,toc:()=>c});var o=n(8168),r=(n(6540),n(5680));const s={sidebar_position:6},i="CustomFunctionMut",u={unversionedId:"storages/developing-custom-storages/store-traits/custom-function-mut",id:"storages/developing-custom-storages/store-traits/custom-function-mut",title:"CustomFunctionMut",description:"By implementing both the CustomFunction and CustomFunctionMut traits, users can create, use, and delete user-level custom functions. Although GlueSQL plans to continuously add various functions, users may still find them insufficient. In such cases, users can create their own user-level custom functions to supplement the built-in functions. Additionally, if there are repetitive business logic codes, they can be stored as custom functions.",source:"@site/docs/storages/developing-custom-storages/store-traits/custom-function-mut.md",sourceDirName:"storages/developing-custom-storages/store-traits",slug:"/storages/developing-custom-storages/store-traits/custom-function-mut",permalink:"/docs/0.16.0/storages/developing-custom-storages/store-traits/custom-function-mut",draft:!1,tags:[],version:"current",sidebarPosition:6,frontMatter:{sidebar_position:6},sidebar:"autoSidebar",previous:{title:"CustomFunction",permalink:"/docs/0.16.0/storages/developing-custom-storages/store-traits/custom-function"},next:{title:"Index",permalink:"/docs/0.16.0/storages/developing-custom-storages/store-traits/index-trait"}},a={},c=[],l={toc:c},m="wrapper";function p(e){let{components:t,...n}=e;return(0,r.yg)(m,(0,o.A)({},l,n,{components:t,mdxType:"MDXLayout"}),(0,r.yg)("h1",{id:"customfunctionmut"},"CustomFunctionMut"),(0,r.yg)("p",null,"By implementing both the ",(0,r.yg)("inlineCode",{parentName:"p"},"CustomFunction")," and ",(0,r.yg)("inlineCode",{parentName:"p"},"CustomFunctionMut")," traits, users can create, use, and delete user-level custom functions. Although GlueSQL plans to continuously add various functions, users may still find them insufficient. In such cases, users can create their own user-level custom functions to supplement the built-in functions. Additionally, if there are repetitive business logic codes, they can be stored as custom functions."),(0,r.yg)("p",null,"Example:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE FUNCTION ADD_ONE (n INT, x INT DEFAULT 1) RETURN n + x;\n\nSELECT ADD_ONE(10) AS test;\n\nDROP FUNCTION ADD_ONE;\n")),(0,r.yg)("p",null,"There are two methods available:"),(0,r.yg)("ol",null,(0,r.yg)("li",{parentName:"ol"},(0,r.yg)("p",{parentName:"li"},(0,r.yg)("inlineCode",{parentName:"p"},"insert_function"),": This method inserts a new custom function into the storage system.")),(0,r.yg)("li",{parentName:"ol"},(0,r.yg)("p",{parentName:"li"},(0,r.yg)("inlineCode",{parentName:"p"},"delete_function"),": This method deletes a custom function from the storage system using the provided function name."))),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-rust"},"#[async_trait(?Send)]\npub trait CustomFunctionMut {\n async fn insert_function(&mut self, _func: StructCustomFunction) -> Result<()>;\n\n async fn delete_function(&mut self, _func_name: &str) -> Result<()>;\n}\n")))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/46076c8b.dd37858a.js b/docs/0.16.0/assets/js/46076c8b.dd37858a.js new file mode 100644 index 00000000..e96d92a8 --- /dev/null +++ b/docs/0.16.0/assets/js/46076c8b.dd37858a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[5169],{6447:e=>{e.exports=JSON.parse('{"permalink":"/docs/0.16.0/blog","page":1,"postsPerPage":10,"totalPages":1,"totalCount":5,"blogDescription":"Blog","blogTitle":"Blog"}')}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/463dc00f.a9cd6d15.js b/docs/0.16.0/assets/js/463dc00f.a9cd6d15.js new file mode 100644 index 00000000..ca61894a --- /dev/null +++ b/docs/0.16.0/assets/js/463dc00f.a9cd6d15.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[4303],{5680:(t,e,n)=>{n.d(e,{xA:()=>l,yg:()=>f});var a=n(6540);function r(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function i(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(t);e&&(a=a.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,a)}return n}function o(t){for(var e=1;e=0||(r[n]=t[n]);return r}(t,e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(t);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(t,n)&&(r[n]=t[n])}return r}var c=a.createContext({}),s=function(t){var e=a.useContext(c),n=e;return t&&(n="function"==typeof t?t(e):o(o({},e),t)),n},l=function(t){var e=s(t.components);return a.createElement(c.Provider,{value:e},t.children)},p="mdxType",u={inlineCode:"code",wrapper:function(t){var e=t.children;return a.createElement(a.Fragment,{},e)}},d=a.forwardRef((function(t,e){var n=t.components,r=t.mdxType,i=t.originalType,c=t.parentName,l=m(t,["components","mdxType","originalType","parentName"]),p=s(n),d=r,f=p["".concat(c,".").concat(d)]||p[d]||u[d]||i;return n?a.createElement(f,o(o({ref:e},l),{},{components:n})):a.createElement(f,o({ref:e},l))}));function f(t,e){var n=arguments,r=e&&e.mdxType;if("string"==typeof t||r){var i=n.length,o=new Array(i);o[0]=d;var m={};for(var c in e)hasOwnProperty.call(e,c)&&(m[c]=e[c]);m.originalType=t,m[p]="string"==typeof t?t:r,o[1]=m;for(var s=2;s{n.r(e),n.d(e,{assets:()=>c,contentTitle:()=>o,default:()=>u,frontMatter:()=>i,metadata:()=>m,toc:()=>s});var a=n(8168),r=(n(6540),n(5680));const i={},o="Formatting",m={unversionedId:"ast-builder/functions/date-&-time/formatting",id:"ast-builder/functions/date-&-time/formatting",title:"Formatting",description:"In GlueSQL, you can format date, time, and timestamp values to a specific format using the format function.",source:"@site/docs/ast-builder/functions/date-&-time/formatting.md",sourceDirName:"ast-builder/functions/date-&-time",slug:"/ast-builder/functions/date-&-time/formatting",permalink:"/docs/0.16.0/ast-builder/functions/date-&-time/formatting",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"Date and Time Extraction",permalink:"/docs/0.16.0/ast-builder/functions/date-&-time/date-and-time-extraction"},next:{title:"List and Map Concatenation",permalink:"/docs/0.16.0/ast-builder/functions/list-&-map/list-and-map-concatenation"}},c={},s=[{value:"Formatting Date",id:"formatting-date",level:2},{value:"Formatting Time",id:"formatting-time",level:2},{value:"Formatting Timestamp",id:"formatting-timestamp",level:2}],l={toc:s},p="wrapper";function u(t){let{components:e,...n}=t;return(0,r.yg)(p,(0,a.A)({},l,n,{components:e,mdxType:"MDXLayout"}),(0,r.yg)("h1",{id:"formatting"},"Formatting"),(0,r.yg)("p",null,"In GlueSQL, you can format date, time, and timestamp values to a specific format using the ",(0,r.yg)("inlineCode",{parentName:"p"},"format")," function."),(0,r.yg)("p",null,"For this tutorial, we assume there's a table named ",(0,r.yg)("inlineCode",{parentName:"p"},"Visitor")," with columns ",(0,r.yg)("inlineCode",{parentName:"p"},"id"),", ",(0,r.yg)("inlineCode",{parentName:"p"},"name"),", ",(0,r.yg)("inlineCode",{parentName:"p"},"visit_date"),", ",(0,r.yg)("inlineCode",{parentName:"p"},"visit_time"),", and ",(0,r.yg)("inlineCode",{parentName:"p"},"visit_timestamp"),"."),(0,r.yg)("h2",{id:"formatting-date"},"Formatting Date"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"format")," function can be used to change the format of a date. "),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Visitor")\n .select()\n .project("name")\n .project("visit_date")\n .project(col("visit_date").format(text("%Y-%m"))) // Formats the visit_date to the year-month format\n .project(format(col("visit_date"), text("%m"))) // Formats the visit_date to the month format\n .execute(glue)\n .await;\n')),(0,r.yg)("h2",{id:"formatting-time"},"Formatting Time"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"format")," function can also be used to change the format of a time."),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Visitor")\n .select()\n .project("name")\n .project("visit_time")\n .project(col("visit_time").format(text("%H:%M:%S"))) // Formats the visit_time to the hour-minute-second format\n .project(format(col("visit_time"), text("%M:%S"))) // Formats the visit_time to the minute-second format\n .execute(glue)\n .await;\n')),(0,r.yg)("h2",{id:"formatting-timestamp"},"Formatting Timestamp"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"format")," function can be used to change the format of a timestamp. "),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Visitor")\n .select()\n .project("name")\n .project("visit_timestamp")\n .project(col("visit_timestamp").format(text("%Y-%m-%d %H:%M:%S"))) // Formats the visit_timestamp to the year-month-date hour-minute-second format\n .project(format(col("visit_timestamp"), text("%Y-%m-%d %H:%M:%S"))) // Formats the visit_timestamp to the year-month-date hour-minute-second format\n .execute(glue)\n .await;\n')))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/47e70afa.c24efe3f.js b/docs/0.16.0/assets/js/47e70afa.c24efe3f.js new file mode 100644 index 00000000..4aa05226 --- /dev/null +++ b/docs/0.16.0/assets/js/47e70afa.c24efe3f.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[4082],{363:s=>{s.exports=JSON.parse('{"label":"nosql","permalink":"/docs/0.16.0/blog/tags/nosql","allTagsPath":"/docs/0.16.0/blog/tags","count":1}')}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/482a391c.b8ab4399.js b/docs/0.16.0/assets/js/482a391c.b8ab4399.js new file mode 100644 index 00000000..443df629 --- /dev/null +++ b/docs/0.16.0/assets/js/482a391c.b8ab4399.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[1416],{5680:(e,t,r)=>{r.d(t,{xA:()=>p,yg:()=>g});var n=r(6540);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function s(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var l=n.createContext({}),c=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},p=function(e){var t=c(e.components);return n.createElement(l.Provider,{value:t},e.children)},m="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,l=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),m=c(r),d=a,g=m["".concat(l,".").concat(d)]||m[d]||u[d]||o;return r?n.createElement(g,s(s({ref:t},p),{},{components:r})):n.createElement(g,s({ref:t},p))}));function g(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,s=new Array(o);s[0]=d;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i[m]="string"==typeof e?e:a,s[1]=i;for(var c=2;c{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>s,default:()=>u,frontMatter:()=>o,metadata:()=>i,toc:()=>c});var n=r(8168),a=(r(6540),r(5680));const o={sidebar_position:1},s="Store",i={unversionedId:"storages/developing-custom-storages/store-traits/store",id:"storages/developing-custom-storages/store-traits/store",title:"Store",description:"The Store trait is the most essential trait to implement for custom storage. Simply by implementing the Store trait, you can support SELECT queries in SQL. You may want to analyze and retrieve data from log files or external APIs using SQL. In this case, having only SELECT queries available is sufficient, and there might not be any need for data modification. In such scenarios, implementing GlueSQL's Store trait alone would be adequate.",source:"@site/docs/storages/developing-custom-storages/store-traits/store.md",sourceDirName:"storages/developing-custom-storages/store-traits",slug:"/storages/developing-custom-storages/store-traits/store",permalink:"/docs/0.16.0/storages/developing-custom-storages/store-traits/store",draft:!1,tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"autoSidebar",previous:{title:"Introduction",permalink:"/docs/0.16.0/storages/developing-custom-storages/intro"},next:{title:"StoreMut",permalink:"/docs/0.16.0/storages/developing-custom-storages/store-traits/store-mut"}},l={},c=[],p={toc:c},m="wrapper";function u(e){let{components:t,...r}=e;return(0,a.yg)(m,(0,n.A)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"store"},"Store"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"Store")," trait is the most essential trait to implement for custom storage. Simply by implementing the Store trait, you can support SELECT queries in SQL. You may want to analyze and retrieve data from log files or external APIs using SQL. In this case, having only SELECT queries available is sufficient, and there might not be any need for data modification. In such scenarios, implementing GlueSQL's ",(0,a.yg)("inlineCode",{parentName:"p"},"Store")," trait alone would be adequate."),(0,a.yg)("p",null,"Here are the four methods required to implement the ",(0,a.yg)("inlineCode",{parentName:"p"},"Store")," trait:"),(0,a.yg)("ol",null,(0,a.yg)("li",{parentName:"ol"},(0,a.yg)("p",{parentName:"li"},(0,a.yg)("inlineCode",{parentName:"p"},"fetch_schema"),": This method is responsible for fetching a schema for a given table name. It returns an optional schema if the table exists.")),(0,a.yg)("li",{parentName:"ol"},(0,a.yg)("p",{parentName:"li"},(0,a.yg)("inlineCode",{parentName:"p"},"fetch_all_schemas"),": This method fetches all the schemas from the storage system. It returns a vector of schemas.")),(0,a.yg)("li",{parentName:"ol"},(0,a.yg)("p",{parentName:"li"},(0,a.yg)("inlineCode",{parentName:"p"},"fetch_data"),": This method fetches a specific data row from the storage system using the provided table name and key. It returns an optional data row if the key exists in the table.")),(0,a.yg)("li",{parentName:"ol"},(0,a.yg)("p",{parentName:"li"},(0,a.yg)("inlineCode",{parentName:"p"},"scan_data"),": This method is used to scan all the data rows in a table. It returns an iterator over the rows in the specified table."))),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-rust"},"pub type RowIter = Box>>;\n\n/// By implementing `Store` trait, you can run `SELECT` query.\n#[async_trait(?Send)]\npub trait Store {\n async fn fetch_schema(&self, table_name: &str) -> Result>;\n\n async fn fetch_all_schemas(&self) -> Result>;\n\n async fn fetch_data(&self, table_name: &str, key: &Key) -> Result>;\n\n async fn scan_data(&self, table_name: &str) -> Result;\n}\n")))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/488157d7.4b4eebc3.js b/docs/0.16.0/assets/js/488157d7.4b4eebc3.js new file mode 100644 index 00000000..8e933588 --- /dev/null +++ b/docs/0.16.0/assets/js/488157d7.4b4eebc3.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[6061],{5680:(e,t,n)=>{n.d(t,{xA:()=>u,yg:()=>m});var r=n(6540);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function s(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var c=r.createContext({}),l=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},u=function(e){var t=l(e.components);return r.createElement(c.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},f=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),p=l(n),f=o,m=p["".concat(c,".").concat(f)]||p[f]||d[f]||a;return n?r.createElement(m,s(s({ref:t},u),{},{components:n})):r.createElement(m,s({ref:t},u))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,s=new Array(a);s[0]=f;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i[p]="string"==typeof e?e:o,s[1]=i;for(var l=2;l{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>s,default:()=>d,frontMatter:()=>a,metadata:()=>i,toc:()=>l});var r=n(8168),o=(n(6540),n(5680));const a={sidebar_position:4},s="Transaction",i={unversionedId:"storages/developing-custom-storages/store-traits/transaction",id:"storages/developing-custom-storages/store-traits/transaction",title:"Transaction",description:"While transactions are often considered an essential feature for databases, GlueSQL treats transactions as an optional trait. Custom storage developers can choose whether or not to support transactions in their storage implementation. Transactions can be quite heavy and expensive in terms of performance.",source:"@site/docs/storages/developing-custom-storages/store-traits/transaction.md",sourceDirName:"storages/developing-custom-storages/store-traits",slug:"/storages/developing-custom-storages/store-traits/transaction",permalink:"/docs/0.16.0/storages/developing-custom-storages/store-traits/transaction",draft:!1,tags:[],version:"current",sidebarPosition:4,frontMatter:{sidebar_position:4},sidebar:"autoSidebar",previous:{title:"AlterTable",permalink:"/docs/0.16.0/storages/developing-custom-storages/store-traits/alter-table"},next:{title:"CustomFunction",permalink:"/docs/0.16.0/storages/developing-custom-storages/store-traits/custom-function"}},c={},l=[],u={toc:l},p="wrapper";function d(e){let{components:t,...n}=e;return(0,o.yg)(p,(0,r.A)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,o.yg)("h1",{id:"transaction"},"Transaction"),(0,o.yg)("p",null,"While transactions are often considered an essential feature for databases, GlueSQL treats transactions as an optional trait. Custom storage developers can choose whether or not to support transactions in their storage implementation. Transactions can be quite heavy and expensive in terms of performance."),(0,o.yg)("p",null,"If you're building a general-purpose OLTP database, transactions are a necessary feature. However, if you want to handle JSONL log files using SQL, transactions may be desirable, but not strictly necessary at the cost of significant performance degradation."),(0,o.yg)("p",null,"You can verify your ",(0,o.yg)("inlineCode",{parentName:"p"},"Transaction")," trait implementation using the Test Suite. However, the Test Suite only provides logical tests for single-threaded environments. If you intend to support transactions in a concurrent environment, you'll need to write additional tests to verify your implementation. This allows different storage implementations to support various transaction isolation levels."),(0,o.yg)("p",null,"Currently, the SAVEPOINT feature is not supported, and only three methods are available: BEGIN (or START TRANSACTION), ROLLBACK, and COMMIT."),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-rust"},"#[async_trait(?Send)]\npub trait Transaction {\n async fn begin(&mut self, autocommit: bool) -> Result;\n\n async fn rollback(&mut self) -> Result<()>;\n\n async fn commit(&mut self) -> Result<()>;\n}\n")))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/4a9d0f4c.65b12999.js b/docs/0.16.0/assets/js/4a9d0f4c.65b12999.js new file mode 100644 index 00000000..9ea26e05 --- /dev/null +++ b/docs/0.16.0/assets/js/4a9d0f4c.65b12999.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[9040],{5680:(e,n,t)=>{t.d(n,{xA:()=>c,yg:()=>m});var r=t(6540);function o(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function i(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function a(e){for(var n=1;n=0||(o[t]=e[t]);return o}(e,n);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var s=r.createContext({}),d=function(e){var n=r.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):a(a({},n),e)),t},c=function(e){var n=d(e.components);return r.createElement(s.Provider,{value:n},e.children)},u="mdxType",p={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},f=r.forwardRef((function(e,n){var t=e.components,o=e.mdxType,i=e.originalType,s=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),u=d(t),f=o,m=u["".concat(s,".").concat(f)]||u[f]||p[f]||i;return t?r.createElement(m,a(a({ref:n},c),{},{components:t})):r.createElement(m,a({ref:n},c))}));function m(e,n){var t=arguments,o=n&&n.mdxType;if("string"==typeof e||o){var i=t.length,a=new Array(i);a[0]=f;var l={};for(var s in n)hasOwnProperty.call(n,s)&&(l[s]=n[s]);l.originalType=e,l[u]="string"==typeof e?e:o,a[1]=l;for(var d=2;d{t.r(n),t.d(n,{assets:()=>s,contentTitle:()=>a,default:()=>p,frontMatter:()=>i,metadata:()=>l,toc:()=>d});var r=t(8168),o=(t(6540),t(5680));const i={},a="MOD",l={unversionedId:"sql-syntax/functions/math/mod",id:"sql-syntax/functions/math/mod",title:"MOD",description:"The MOD function is used to calculate the remainder of a division operation. It takes two arguments (a dividend and a divisor) and returns the remainder of the division operation. Both dividend and divisor can be FLOAT or INTEGER type. The return type of the function is FLOAT.",source:"@site/docs/sql-syntax/functions/math/mod.md",sourceDirName:"sql-syntax/functions/math",slug:"/sql-syntax/functions/math/mod",permalink:"/docs/0.16.0/sql-syntax/functions/math/mod",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"LOG2",permalink:"/docs/0.16.0/sql-syntax/functions/math/log2"},next:{title:"PI",permalink:"/docs/0.16.0/sql-syntax/functions/math/pi"}},s={},d=[{value:"Example",id:"example",level:2},{value:"Errors",id:"errors",level:2}],c={toc:d},u="wrapper";function p(e){let{components:n,...t}=e;return(0,o.yg)(u,(0,r.A)({},c,t,{components:n,mdxType:"MDXLayout"}),(0,o.yg)("h1",{id:"mod"},"MOD"),(0,o.yg)("p",null,"The ",(0,o.yg)("inlineCode",{parentName:"p"},"MOD")," function is used to calculate the remainder of a division operation. It takes two arguments (a dividend and a divisor) and returns the remainder of the division operation. Both dividend and divisor can be FLOAT or INTEGER type. The return type of the function is FLOAT."),(0,o.yg)("h2",{id:"example"},"Example"),(0,o.yg)("p",null,"The following example demonstrates the usage of the ",(0,o.yg)("inlineCode",{parentName:"p"},"MOD")," function in a SQL query:"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE FloatDiv (\n dividend FLOAT DEFAULT MOD(30, 11),\n divisor FLOAT DEFAULT DIV(3, 2)\n);\n\nINSERT INTO FloatDiv (dividend, divisor) VALUES (12.0, 3.0), (12.34, 56.78), (-12.3, 4.0);\n\nSELECT MOD(dividend, divisor) FROM FloatDiv;\n")),(0,o.yg)("p",null,"This will return the following result:"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre"},"MOD(dividend, divisor)\n0.0\n12.34\n-0.3\n")),(0,o.yg)("h2",{id:"errors"},"Errors"),(0,o.yg)("ol",null,(0,o.yg)("li",{parentName:"ol"},"If the divisor is zero, a ",(0,o.yg)("inlineCode",{parentName:"li"},"DivisorShouldNotBeZero")," error will be raised."),(0,o.yg)("li",{parentName:"ol"},"If either of the arguments is not of FLOAT or INTEGER type, a ",(0,o.yg)("inlineCode",{parentName:"li"},"FunctionRequiresFloatOrIntegerValue")," error will be raised."),(0,o.yg)("li",{parentName:"ol"},"If the number of arguments provided to the function is not equal to 2, a ",(0,o.yg)("inlineCode",{parentName:"li"},"FunctionArgsLengthNotMatching")," error will be raised.")))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/4aa001c0.c8372f9f.js b/docs/0.16.0/assets/js/4aa001c0.c8372f9f.js new file mode 100644 index 00000000..7df18691 --- /dev/null +++ b/docs/0.16.0/assets/js/4aa001c0.c8372f9f.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[8317],{5680:(e,n,t)=>{t.d(n,{xA:()=>p,yg:()=>y});var a=t(6540);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function i(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function o(e){for(var n=1;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var d=a.createContext({}),s=function(e){var n=a.useContext(d),t=n;return e&&(t="function"==typeof e?e(n):o(o({},n),e)),t},p=function(e){var n=s(e.components);return a.createElement(d.Provider,{value:n},e.children)},u="mdxType",c={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},m=a.forwardRef((function(e,n){var t=e.components,r=e.mdxType,i=e.originalType,d=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),u=s(t),m=r,y=u["".concat(d,".").concat(m)]||u[m]||c[m]||i;return t?a.createElement(y,o(o({ref:n},p),{},{components:t})):a.createElement(y,o({ref:n},p))}));function y(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var i=t.length,o=new Array(i);o[0]=m;var l={};for(var d in n)hasOwnProperty.call(n,d)&&(l[d]=n[d]);l.originalType=e,l[u]="string"==typeof e?e:r,o[1]=l;for(var s=2;s{t.r(n),t.d(n,{assets:()=>d,contentTitle:()=>o,default:()=>c,frontMatter:()=>i,metadata:()=>l,toc:()=>s});var a=t(8168),r=(t(6540),t(5680));const i={sidebar_position:4},o="DROP INDEX",l={unversionedId:"sql-syntax/statements/data-definition/drop-index",id:"sql-syntax/statements/data-definition/drop-index",title:"DROP INDEX",description:"DROP INDEX statement is used to remove an existing index from a table. This can be useful when an index is no longer needed, or if you want to free up storage space and reduce maintenance overhead associated with maintaining the index.",source:"@site/docs/sql-syntax/statements/data-definition/drop-index.md",sourceDirName:"sql-syntax/statements/data-definition",slug:"/sql-syntax/statements/data-definition/drop-index",permalink:"/docs/0.16.0/sql-syntax/statements/data-definition/drop-index",draft:!1,tags:[],version:"current",sidebarPosition:4,frontMatter:{sidebar_position:4},sidebar:"autoSidebar",previous:{title:"CREATE INDEX",permalink:"/docs/0.16.0/sql-syntax/statements/data-definition/create-index"},next:{title:"ALTER TABLE",permalink:"/docs/0.16.0/sql-syntax/statements/data-definition/alter-table"}},d={},s=[{value:"Syntax",id:"syntax",level:2},{value:"Example",id:"example",level:2}],p={toc:s},u="wrapper";function c(e){let{components:n,...t}=e;return(0,r.yg)(u,(0,a.A)({},p,t,{components:n,mdxType:"MDXLayout"}),(0,r.yg)("h1",{id:"drop-index"},"DROP INDEX"),(0,r.yg)("p",null,(0,r.yg)("inlineCode",{parentName:"p"},"DROP INDEX")," statement is used to remove an existing index from a table. This can be useful when an index is no longer needed, or if you want to free up storage space and reduce maintenance overhead associated with maintaining the index."),(0,r.yg)("h2",{id:"syntax"},"Syntax"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"DROP INDEX table_name.index_name;\n")),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"table_name"),": The name of the table containing the index to be dropped."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"index_name"),": The name of the index to be dropped.")),(0,r.yg)("p",null,"Note that only one index can be dropped at a time using the ",(0,r.yg)("inlineCode",{parentName:"p"},"DROP INDEX")," statement. If you want to drop multiple indexes, you need to execute multiple ",(0,r.yg)("inlineCode",{parentName:"p"},"DROP INDEX")," statements."),(0,r.yg)("h2",{id:"example"},"Example"),(0,r.yg)("p",null,"Consider the following table called ",(0,r.yg)("inlineCode",{parentName:"p"},"Students")," with an index on the ",(0,r.yg)("inlineCode",{parentName:"p"},"id")," column:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE Students (\n id INTEGER,\n age INTEGER,\n name TEXT\n);\n\nCREATE INDEX idx_id ON Students (id);\n")),(0,r.yg)("p",null,"You can drop the ",(0,r.yg)("inlineCode",{parentName:"p"},"idx_id")," index with the following statement:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"DROP INDEX Students.idx_id;\n")),(0,r.yg)("p",null,"If you attempt to drop multiple indexes in a single statement, an error will be raised:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"DROP INDEX Students.idx_id, Students.idx_age;\n")),(0,r.yg)("p",null,"This will result in an error, as only one index can be dropped at a time. To drop both indexes, execute two separate ",(0,r.yg)("inlineCode",{parentName:"p"},"DROP INDEX")," statements:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"DROP INDEX Students.idx_id;\nDROP INDEX Students.idx_age;\n")))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/4add0c6c.7ed8ffdc.js b/docs/0.16.0/assets/js/4add0c6c.7ed8ffdc.js new file mode 100644 index 00000000..58da903a --- /dev/null +++ b/docs/0.16.0/assets/js/4add0c6c.7ed8ffdc.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[9564],{5680:(e,t,r)=>{r.d(t,{xA:()=>c,yg:()=>y});var n=r(6540);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function l(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var o=n.createContext({}),s=function(e){var t=n.useContext(o),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},c=function(e){var t=s(e.components);return n.createElement(o.Provider,{value:t},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},g=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,l=e.originalType,o=e.parentName,c=u(e,["components","mdxType","originalType","parentName"]),d=s(r),g=a,y=d["".concat(o,".").concat(g)]||d[g]||p[g]||l;return r?n.createElement(y,i(i({ref:t},c),{},{components:r})):n.createElement(y,i({ref:t},c))}));function y(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var l=r.length,i=new Array(l);i[0]=g;var u={};for(var o in t)hasOwnProperty.call(t,o)&&(u[o]=t[o]);u.originalType=e,u[d]="string"==typeof e?e:a,i[1]=u;for(var s=2;s{r.r(t),r.d(t,{assets:()=>o,contentTitle:()=>i,default:()=>p,frontMatter:()=>l,metadata:()=>u,toc:()=>s});var n=r(8168),a=(r(6540),r(5680));const l={title:"Introduction",sidebar_position:1},i="AST Builder",u={unversionedId:"ast-builder/intro",id:"ast-builder/intro",title:"Introduction",description:"GlueSQL offers two ways to create and execute queries: using SQL statements or using the AST Builder. In this introductory page, we will focus on the AST Builder.",source:"@site/docs/ast-builder/intro.md",sourceDirName:"ast-builder",slug:"/ast-builder/intro",permalink:"/docs/0.16.0/ast-builder/intro",draft:!1,tags:[],version:"current",sidebarPosition:1,frontMatter:{title:"Introduction",sidebar_position:1},sidebar:"autoSidebar",previous:{title:"IFNULL",permalink:"/docs/0.16.0/sql-syntax/functions/others/ifnull"},next:{title:"Fetching Data from Storage",permalink:"/docs/0.16.0/ast-builder/statements/querying/fetching-data-from-storage"}},o={},s=[{value:"CREATE TABLE",id:"create-table",level:3},{value:"INSERT",id:"insert",level:3},{value:"SELECT",id:"select",level:3},{value:"UPDATE",id:"update",level:3},{value:"SELECT with filtering",id:"select-with-filtering",level:3},{value:"DELETE",id:"delete",level:3},{value:"Summary",id:"summary",level:2}],c={toc:s},d="wrapper";function p(e){let{components:t,...r}=e;return(0,a.yg)(d,(0,n.A)({},c,r,{components:t,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"ast-builder"},"AST Builder"),(0,a.yg)("p",null,"GlueSQL offers two ways to create and execute queries: using SQL statements or using the AST Builder. In this introductory page, we will focus on the AST Builder."),(0,a.yg)("p",null,"When executing SQL statements in GlueSQL, they need to be converted into an internal AST (Abstract Syntax Tree) format. The AST Builder allows users to directly create and manipulate ASTs, making it more efficient and flexible compared to traditional SQL statements."),(0,a.yg)("p",null,"The AST Builder has some similarities to ORM (Object Relational Mapping) query builders, but there are several key differences:"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},"ORM query builders often support multiple databases, which can limit their features to a subset of each database's capabilities. However, the AST Builder is designed exclusively for GlueSQL, allowing it to take full advantage of all GlueSQL features."),(0,a.yg)("li",{parentName:"ul"},"The AST Builder is flexible in terms of input, accepting both its own API calls and SQL expressions."),(0,a.yg)("li",{parentName:"ul"},"ORM query builders typically generate SQL statements, which must then be executed by the database. This introduces overhead. In contrast, the GlueSQL AST Builder directly generates executable ASTs, making it highly efficient."),(0,a.yg)("li",{parentName:"ul"},"The AST Builder supports features that are not available with SQL, such as allowing users to directly specify the internal execution strategy. This is similar to SQL query hints, but with the AST Builder, the user's instructions are executed precisely, rather than being treated as suggestions.")),(0,a.yg)("p",null,"Currently, the AST Builder only supports Rust language interfaces, but support for other languages, such as JavaScript, is planned for future releases."),(0,a.yg)("p",null,"Below are some sample code snippets using the GlueSQL AST Builder in Rust, categorized by query type:"),(0,a.yg)("h3",{id:"create-table"},"CREATE TABLE"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Foo")\n .create_table()\n .add_column("id INTEGER")\n .add_column("name TEXT")\n .execute(glue)\n .await;\n')),(0,a.yg)("h3",{id:"insert"},"INSERT"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Foo")\n .insert()\n .columns("id, name")\n .values(vec![\n vec![num(100), text("Pickle")],\n vec![num(200), text("Lemon")],\n ])\n .execute(glue)\n .await;\n')),(0,a.yg)("h3",{id:"select"},"SELECT"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Foo")\n .select()\n .project("id, name")\n .execute(glue)\n .await;\n')),(0,a.yg)("h3",{id:"update"},"UPDATE"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Foo")\n .update()\n .set("id", col("id").mul(2))\n .filter(col("id").eq(200))\n .execute(glue)\n .await;\n')),(0,a.yg)("h3",{id:"select-with-filtering"},"SELECT with filtering"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Foo")\n .select()\n .filter("name = \'Lemon\'")\n .project("id, name")\n .build()\n .expect("build and execute")\n .execute(glue)\n .await;\n')),(0,a.yg)("h3",{id:"delete"},"DELETE"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Foo")\n .delete()\n .filter(col("id").gt(200))\n .execute(glue)\n .await;\n')),(0,a.yg)("h2",{id:"summary"},"Summary"),(0,a.yg)("p",null,"In this introduction to the AST Builder, we have covered the key differences between the AST Builder and ORM query builders, and provided examples of how to use the AST Builder in Rust for various query types. The AST Builder is a powerful and efficient tool for working with GlueSQL, offering greater flexibility and control compared to traditional SQL statements."),(0,a.yg)("p",null,"Remember that the AST Builder currently supports only Rust language interfaces, but support for other languages, such as JavaScript, is planned for future releases."),(0,a.yg)("p",null,"By leveraging the AST Builder, you can take full advantage of GlueSQL's features, and build more efficient and flexible database applications."))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/4be897c9.e7b3c387.js b/docs/0.16.0/assets/js/4be897c9.e7b3c387.js new file mode 100644 index 00000000..a1efb56c --- /dev/null +++ b/docs/0.16.0/assets/js/4be897c9.e7b3c387.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[9350],{5680:(e,t,n)=>{n.d(t,{xA:()=>l,yg:()=>f});var r=n(6540);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),u=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},l=function(e){var t=u(e.components);return r.createElement(s.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},y=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),p=u(n),y=a,f=p["".concat(s,".").concat(y)]||p[y]||d[y]||o;return n?r.createElement(f,i(i({ref:t},l),{},{components:n})):r.createElement(f,i({ref:t},l))}));function f(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=y;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c[p]="string"==typeof e?e:a,i[1]=c;for(var u=2;u{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>d,frontMatter:()=>o,metadata:()=>c,toc:()=>u});var r=n(8168),a=(n(6540),n(5680));const o={},i="Data Injection",c={unversionedId:"ast-builder/statements/querying/data-injection",id:"ast-builder/statements/querying/data-injection",title:"Data Injection",description:"Todo",source:"@site/docs/ast-builder/statements/querying/data-injection.md",sourceDirName:"ast-builder/statements/querying",slug:"/ast-builder/statements/querying/data-injection",permalink:"/docs/0.16.0/ast-builder/statements/querying/data-injection",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"Data Aggregation",permalink:"/docs/0.16.0/ast-builder/statements/querying/data-aggregation"},next:{title:"Data Joining",permalink:"/docs/0.16.0/ast-builder/statements/querying/data-joining"}},s={},u=[{value:"Todo",id:"todo",level:2}],l={toc:u},p="wrapper";function d(e){let{components:t,...n}=e;return(0,a.yg)(p,(0,r.A)({},l,n,{components:t,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"data-injection"},"Data Injection"),(0,a.yg)("h2",{id:"todo"},"Todo"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre"},"- VALUES: Allows users to manually input data into the query.\n")))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/4d9df5b1.71153059.js b/docs/0.16.0/assets/js/4d9df5b1.71153059.js new file mode 100644 index 00000000..dbe10c96 --- /dev/null +++ b/docs/0.16.0/assets/js/4d9df5b1.71153059.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[7540],{5680:(e,t,n)=>{n.d(t,{xA:()=>u,yg:()=>f});var r=n(6540);function l(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function a(e){for(var t=1;t=0||(l[n]=e[n]);return l}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(l[n]=e[n])}return l}var s=r.createContext({}),c=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},u=function(e){var t=c(e.components);return r.createElement(s.Provider,{value:t},e.children)},p="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},y=r.forwardRef((function(e,t){var n=e.components,l=e.mdxType,i=e.originalType,s=e.parentName,u=o(e,["components","mdxType","originalType","parentName"]),p=c(n),y=l,f=p["".concat(s,".").concat(y)]||p[y]||m[y]||i;return n?r.createElement(f,a(a({ref:t},u),{},{components:n})):r.createElement(f,a({ref:t},u))}));function f(e,t){var n=arguments,l=t&&t.mdxType;if("string"==typeof e||l){var i=n.length,a=new Array(i);a[0]=y;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[p]="string"==typeof e?e:l,a[1]=o;for(var c=2;c{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>a,default:()=>m,frontMatter:()=>i,metadata:()=>o,toc:()=>c});var r=n(8168),l=(n(6540),n(5680));const i={},a='SQL Function - "SPLICE"',o={unversionedId:"sql-syntax/functions/list-map/splice",id:"sql-syntax/functions/list-map/splice",title:'SQL Function - "SPLICE"',description:'The "SPLICE" function in GlueSQL is used to modify elements in a list. It allows you to remove or replace elements in a list. The syntax for the "SPLICE" function is as follows:',source:"@site/docs/sql-syntax/functions/list-map/splice.md",sourceDirName:"sql-syntax/functions/list-map",slug:"/sql-syntax/functions/list-map/splice",permalink:"/docs/0.16.0/sql-syntax/functions/list-map/splice",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"SLICE",permalink:"/docs/0.16.0/sql-syntax/functions/list-map/slice"},next:{title:"CALC_DISTANCE",permalink:"/docs/0.16.0/sql-syntax/functions/geometry/calc-distance"}},s={},c=[{value:"Example",id:"example",level:2},{value:"Error",id:"error",level:2}],u={toc:c},p="wrapper";function m(e){let{components:t,...n}=e;return(0,l.yg)(p,(0,r.A)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,l.yg)("h1",{id:"sql-function---splice"},'SQL Function - "SPLICE"'),(0,l.yg)("p",null,'The "SPLICE" function in GlueSQL is used to modify elements in a list. It allows you to remove or replace elements in a list. The syntax for the "SPLICE" function is as follows:'),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"SPLICE(list1, start_index, end_index [, list2])\n")),(0,l.yg)("ul",null,(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("inlineCode",{parentName:"li"},"list1"),": The list you want to modify."),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("inlineCode",{parentName:"li"},"start_index"),": The position at which you want to start the modification."),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("inlineCode",{parentName:"li"},"end_index"),": The exclusive end position for the modification."),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("inlineCode",{parentName:"li"},"list2")," (optional): A list of elements to insert in place of the removed elements.")),(0,l.yg)("h2",{id:"example"},"Example"),(0,l.yg)("p",null,'We can use the "SPLICE" function to modify the list in various ways:'),(0,l.yg)("ol",null,(0,l.yg)("li",{parentName:"ol"},"Remove elements from a list:")),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"-- Remove elements at 1, 2 from the list '[1, 2, 3]'\nSELECT SPLICE(CAST('[1, 2, 3, 4, 5]' AS List), 1, 3) AS result;\n-- Output: '[1, 4, 5]'\n")),(0,l.yg)("ol",{start:2},(0,l.yg)("li",{parentName:"ol"},"Replace elements in a list:")),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"-- Replace elements at 1, 2, 3 with '[100, 99]' in the list '[1, 2, 3, 4, 5]'\nSELECT SPLICE(CAST('[1, 2, 3, 4, 5]' AS List), 1, 4, CAST('[100, 99]' AS List)) AS result;\n-- Output: '[1, 100, 99, 5]'\n")),(0,l.yg)("ol",{start:3},(0,l.yg)("li",{parentName:"ol"},"'start' is processed so that it is not less than 0 and 'end' is not greater than the length of the list.")),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT SPLICE(CAST('[1, 2, 3]' AS List), -1, 2, CAST('[100, 99]' AS List)) AS result;\n-- Output: '[100, 99, 3]'\n")),(0,l.yg)("h2",{id:"error"},"Error"),(0,l.yg)("p",null,'If you use the "SPLICE" function with invalid inputs, it will result in an error. For example:'),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"-- Using SPLICE on a non-list value will result in an error.\nSELECT SPLICE(3, 1, 2) AS result;\n-- EvaluateError::ListTypeRequired\n")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/4f675ae9.2aee3ba3.js b/docs/0.16.0/assets/js/4f675ae9.2aee3ba3.js new file mode 100644 index 00000000..46725047 --- /dev/null +++ b/docs/0.16.0/assets/js/4f675ae9.2aee3ba3.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[4784],{5680:(e,t,n)=>{n.d(t,{xA:()=>c,yg:()=>d});var a=n(6540);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function l(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var p=a.createContext({}),s=function(e){var t=a.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},c=function(e){var t=s(e.components);return a.createElement(p.Provider,{value:t},e.children)},m="mdxType",y={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},g=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,p=e.parentName,c=o(e,["components","mdxType","originalType","parentName"]),m=s(n),g=r,d=m["".concat(p,".").concat(g)]||m[g]||y[g]||i;return n?a.createElement(d,l(l({ref:t},c),{},{components:n})):a.createElement(d,l({ref:t},c))}));function d(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,l=new Array(i);l[0]=g;var o={};for(var p in t)hasOwnProperty.call(t,p)&&(o[p]=t[p]);o.originalType=e,o[m]="string"==typeof e?e:r,l[1]=o;for(var s=2;s{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>l,default:()=>y,frontMatter:()=>i,metadata:()=>o,toc:()=>s});var a=n(8168),r=(n(6540),n(5680));const i={},l="EXTRACT",o={unversionedId:"sql-syntax/functions/datetime/extract",id:"sql-syntax/functions/datetime/extract",title:"EXTRACT",description:"The EXTRACT function in SQL is used to retrieve a specific datetime field from a date, time, or interval.",source:"@site/docs/sql-syntax/functions/datetime/extract.md",sourceDirName:"sql-syntax/functions/datetime",slug:"/sql-syntax/functions/datetime/extract",permalink:"/docs/0.16.0/sql-syntax/functions/datetime/extract",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"TAN",permalink:"/docs/0.16.0/sql-syntax/functions/math/tan"},next:{title:"FORMAT",permalink:"/docs/0.16.0/sql-syntax/functions/datetime/format"}},p={},s=[{value:"Syntax",id:"syntax",level:2},{value:"Usage",id:"usage",level:2}],c={toc:s},m="wrapper";function y(e){let{components:t,...n}=e;return(0,r.yg)(m,(0,a.A)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,r.yg)("h1",{id:"extract"},"EXTRACT"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"EXTRACT")," function in SQL is used to retrieve a specific datetime field from a date, time, or interval. "),(0,r.yg)("h2",{id:"syntax"},"Syntax"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"EXTRACT(field FROM source)\n")),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"field"),": The datetime field to extract. Valid fields include ",(0,r.yg)("inlineCode",{parentName:"li"},"YEAR"),", ",(0,r.yg)("inlineCode",{parentName:"li"},"MONTH"),", ",(0,r.yg)("inlineCode",{parentName:"li"},"DAY"),", ",(0,r.yg)("inlineCode",{parentName:"li"},"HOUR"),", ",(0,r.yg)("inlineCode",{parentName:"li"},"MINUTE"),", ",(0,r.yg)("inlineCode",{parentName:"li"},"SECOND"),"."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"source"),": The date, time, or interval value from which the datetime field is to be extracted.")),(0,r.yg)("h2",{id:"usage"},"Usage"),(0,r.yg)("p",null,"Here are examples of how ",(0,r.yg)("inlineCode",{parentName:"p"},"EXTRACT")," can be used to pull specific datetime components from various types of datetime and interval data. "),(0,r.yg)("ol",null,(0,r.yg)("li",{parentName:"ol"},(0,r.yg)("p",{parentName:"li"},"Extracting the ",(0,r.yg)("inlineCode",{parentName:"p"},"HOUR")," from a ",(0,r.yg)("inlineCode",{parentName:"p"},"TIMESTAMP"),": "),(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT EXTRACT(HOUR FROM TIMESTAMP '2016-12-31 13:30:15') as extract;\n")),(0,r.yg)("p",{parentName:"li"},"This returns ",(0,r.yg)("inlineCode",{parentName:"p"},"13"),".")),(0,r.yg)("li",{parentName:"ol"},(0,r.yg)("p",{parentName:"li"},"Extracting the ",(0,r.yg)("inlineCode",{parentName:"p"},"YEAR")," from a ",(0,r.yg)("inlineCode",{parentName:"p"},"TIMESTAMP"),": "),(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT EXTRACT(YEAR FROM TIMESTAMP '2016-12-31 13:30:15') as extract;\n")),(0,r.yg)("p",{parentName:"li"},"This returns ",(0,r.yg)("inlineCode",{parentName:"p"},"2016"),".")),(0,r.yg)("li",{parentName:"ol"},(0,r.yg)("p",{parentName:"li"},"Extracting the ",(0,r.yg)("inlineCode",{parentName:"p"},"SECOND")," from a ",(0,r.yg)("inlineCode",{parentName:"p"},"TIME")," value: "),(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT EXTRACT(SECOND FROM TIME '17:12:28') as extract;\n")),(0,r.yg)("p",{parentName:"li"},"This returns ",(0,r.yg)("inlineCode",{parentName:"p"},"28"),".")),(0,r.yg)("li",{parentName:"ol"},(0,r.yg)("p",{parentName:"li"},"Extracting the ",(0,r.yg)("inlineCode",{parentName:"p"},"DAY")," from a ",(0,r.yg)("inlineCode",{parentName:"p"},"DATE")," value: "),(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT EXTRACT(DAY FROM DATE '2021-10-06') as extract;\n")),(0,r.yg)("p",{parentName:"li"},"This returns ",(0,r.yg)("inlineCode",{parentName:"p"},"6"),".")),(0,r.yg)("li",{parentName:"ol"},(0,r.yg)("p",{parentName:"li"},"Extracting from ",(0,r.yg)("inlineCode",{parentName:"p"},"INTERVAL")," data: "),(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT EXTRACT(YEAR FROM INTERVAL '3' YEAR) as extract;\nSELECT EXTRACT(MINUTE FROM INTERVAL '7' MINUTE) as extract;\n")),(0,r.yg)("p",{parentName:"li"},"These return ",(0,r.yg)("inlineCode",{parentName:"p"},"3")," and ",(0,r.yg)("inlineCode",{parentName:"p"},"7"),", respectively."))),(0,r.yg)("p",null,"Note that the ",(0,r.yg)("inlineCode",{parentName:"p"},"EXTRACT")," function expects the ",(0,r.yg)("inlineCode",{parentName:"p"},"source")," to be of a compatible datetime or interval type. Using a value of an incompatible type, such as a number or a string that cannot be interpreted as a datetime, will result in an error."))}y.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/5058a078.d2f3c214.js b/docs/0.16.0/assets/js/5058a078.d2f3c214.js new file mode 100644 index 00000000..0db989ab --- /dev/null +++ b/docs/0.16.0/assets/js/5058a078.d2f3c214.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[8505],{5680:(e,t,n)=>{n.d(t,{xA:()=>c,yg:()=>p});var a=n(6540);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function s(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var l=a.createContext({}),u=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},c=function(e){var t=u(e.components);return a.createElement(l.Provider,{value:t},e.children)},d="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,l=e.parentName,c=r(e,["components","mdxType","originalType","parentName"]),d=u(n),m=o,p=d["".concat(l,".").concat(m)]||d[m]||h[m]||i;return n?a.createElement(p,s(s({ref:t},c),{},{components:n})):a.createElement(p,s({ref:t},c))}));function p(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,s=new Array(i);s[0]=m;var r={};for(var l in t)hasOwnProperty.call(t,l)&&(r[l]=t[l]);r.originalType=e,r[d]="string"==typeof e?e:o,s[1]=r;for(var u=2;u{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>s,default:()=>h,frontMatter:()=>i,metadata:()=>r,toc:()=>u});var a=n(8168),o=(n(6540),n(5680));const i={title:"Test-Driven Documentation - Automating User Manual Creation in GlueSQL",description:"Test-Driven Documentation - Automating User Manual Creation in GlueSQL",slug:"test-driven-documentation",authors:[{name:"Taehoon Moon",title:"Creator of GlueSQL",url:"https://github.com/panarch",image_url:"https://github.com/panarch.png"}],tags:["ChatGPT","Test-Driven-Documentation","TDD","Database","Documentation","Automation"]},s="Test-Driven Documentation - Automating User Manual Creation in GlueSQL",r={permalink:"/docs/0.16.0/blog/test-driven-documentation",source:"@site/blog/2023-05-30-test-driven-documentation.md",title:"Test-Driven Documentation - Automating User Manual Creation in GlueSQL",description:"Test-Driven Documentation - Automating User Manual Creation in GlueSQL",date:"2023-05-30T00:00:00.000Z",formattedDate:"May 30, 2023",tags:[{label:"ChatGPT",permalink:"/docs/0.16.0/blog/tags/chat-gpt"},{label:"Test-Driven-Documentation",permalink:"/docs/0.16.0/blog/tags/test-driven-documentation"},{label:"TDD",permalink:"/docs/0.16.0/blog/tags/tdd"},{label:"Database",permalink:"/docs/0.16.0/blog/tags/database"},{label:"Documentation",permalink:"/docs/0.16.0/blog/tags/documentation"},{label:"Automation",permalink:"/docs/0.16.0/blog/tags/automation"}],readingTime:9.265,hasTruncateMarker:!1,authors:[{name:"Taehoon Moon",title:"Creator of GlueSQL",url:"https://github.com/panarch",image_url:"https://github.com/panarch.png",imageURL:"https://github.com/panarch.png"}],frontMatter:{title:"Test-Driven Documentation - Automating User Manual Creation in GlueSQL",description:"Test-Driven Documentation - Automating User Manual Creation in GlueSQL",slug:"test-driven-documentation",authors:[{name:"Taehoon Moon",title:"Creator of GlueSQL",url:"https://github.com/panarch",image_url:"https://github.com/panarch.png",imageURL:"https://github.com/panarch.png"}],tags:["ChatGPT","Test-Driven-Documentation","TDD","Database","Documentation","Automation"]},prevItem:{title:"GlueSQL - Revolutionizing Databases by Unifying Query Interfaces",permalink:"/docs/0.16.0/blog/revolutionizing-databases-by-unifying-query-interfaces"},nextItem:{title:"Breaking the Boundary between SQL and NoSQL Databases",permalink:"/docs/0.16.0/blog/breaking-the-boundary-between-sql-and-nosql"}},l={authorsImageUrls:[void 0]},u=[{value:"Introduction: GlueSQL and Test-Driven Documentation",id:"introduction-gluesql-and-test-driven-documentation",level:2},{value:"Test Codes and Documentation",id:"test-codes-and-documentation",level:2},{value:"Leveraging ChatGPT",id:"leveraging-chatgpt",level:2},{value:"Success Case: Automated User Manual of GlueSQL",id:"success-case-automated-user-manual-of-gluesql",level:2},{value:"Future Plans: Fully Automating Documentation Generation",id:"future-plans-fully-automating-documentation-generation",level:2},{value:"Conclusion: The Value of Test-Driven Documentation",id:"conclusion-the-value-of-test-driven-documentation",level:2}],c={toc:u},d="wrapper";function h(e){let{components:t,...i}=e;return(0,o.yg)(d,(0,a.A)({},c,i,{components:t,mdxType:"MDXLayout"}),(0,o.yg)("h2",{id:"introduction-gluesql-and-test-driven-documentation"},"Introduction: GlueSQL and Test-Driven Documentation"),(0,o.yg)("p",null,"Recently, the GlueSQL project reached a significant milestone with the release of version 0.14. This new version brings a host of fresh features to the table, yet one of the most notable changes is in the realm of documentation. For the first time, we're proud to announce the launch of our official documentation website. Interested readers can explore the full range of user manuals at ",(0,o.yg)("a",{parentName:"p",href:"https://gluesql.org/docs"},"https://gluesql.org/docs"),"."),(0,o.yg)("p",null,"Prior to this update, the only way to navigate GlueSQL was by manually inspecting the test code within the test suite. With the recent release, however, a comprehensive user manual has been made public to facilitate a more user-friendly experience. We hope that this new addition will prove beneficial to a broad spectrum of users."),(0,o.yg)("p",null,"The task of compiling an entire database manual in one go was daunting due to the sheer volume of content required. Surprisingly, this process turned out to be smoother than initially anticipated, largely due to the invaluable aid of ChatGPT, which was instrumental in automating much of the document creation. Specifically, around 80% of the SQL Syntax section was generated using this tool."),(0,o.yg)("p",null,"This remarkable feat was only possible due to the solid foundation of test codes previously established in GlueSQL. In this article, we'll share how we managed to leverage ChatGPT in such a unique way. Based on our recent experience of crafting documents grounded in testing, we've begun to consider the possibility of entirely automating document creation, save for the initial stages."),(0,o.yg)("p",null,"Along with sharing our journey so far, we will also reveal our plans for future test-based automation of documentation within GlueSQL."),(0,o.yg)("h2",{id:"test-codes-and-documentation"},"Test Codes and Documentation"),(0,o.yg)("p",null,"The GlueSQL project has placed a significant emphasis on writing test codes. This might be a given for a database project; however, the thoroughness of our approach is evident from our line coverage of nearly ",(0,o.yg)("strong",{parentName:"p"},"99%")," for core codes. While we devoted considerable effort to creating these test codes, our primary focus has always been on a different aspect: ensuring that anyone can quickly grasp the content of the tests and easily add new ones."),(0,o.yg)("p",null,"The intent here is to empower newcomers to GlueSQL to understand the functionality of the software solely by examining integration tests, even in the absence of a user manual."),(0,o.yg)("p",null,"The integration tests for GlueSQL can be found in the test-suite workspace. For example, here's an excerpt of the test code for the INSERT statement:"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-rust"},'test_case!(insert, async move {\n run!(\n "\nCREATE TABLE Test (\n id INTEGER DEFAULT 1,\n num INTEGER NULL,\n name TEXT NOT NULL,\n);"\n );\n\n test! {\n name: "basic insert - single item",\n sql: "INSERT INTO Test (id, num, name) VALUES (1, 2, \'Hi boo\');",\n expected: Ok(Payload::Insert(1))\n };\n\n\n test! {\n sql: "INSERT INTO Test VALUES(17, 30, \'Sullivan\');",\n expected: Ok(Payload::Insert(1))\n };\n\n test! {\n sql: "INSERT INTO Test (num, name) VALUES (28, \'Wazowski\');",\n expected: Ok(Payload::Insert(1))\n };\n\n test! {\n sql: "SELECT * FROM Test;",\n expected: Ok(select!(\n id | num | name;\n I64 | I64 | Str;\n 1 2 "Hi boo".to_owned();\n 3 9 "Kitty!".to_owned();\n 2 7 "Monsters".to_owned();\n 17 30 "Sullivan".to_owned();\n 1 28 "Wazowski".to_owned()\n ))\n };\n\n // ...\n});\n')),(0,o.yg)("p",null,"Despite being written in Rust, these test cases are designed to be comprehensible, even to those unfamiliar with the language. Each test is a complete scenario from start to finish, and the results of each operation are readily observable."),(0,o.yg)("p",null,"Given that identifying results from SELECT operations in the form of Rust enums and structs can be challenging, we actively utilized macros such as ",(0,o.yg)("inlineCode",{parentName:"p"},"select!")," and ",(0,o.yg)("inlineCode",{parentName:"p"},"select_with_null!"),". We've composed the test cases to demonstrate that the INSERT statement can handle a wide range of cases, including specifying all columns, omitting some, or omitting all."),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-rust"},'test! {\n sql: "INSERT INTO Test (id, num) VALUES (1, 10);",\n expected: Err(InsertError::LackOfRequiredColumn("name".to_owned()).into())\n};\n')),(0,o.yg)("p",null,"The tests also include scenarios for expected faulty inputs, indicating the error returns in these situations."),(0,o.yg)("p",null,"By organizing the tests in this manner, we aim to make it easy for anyone to read and write tests. Our goal was for these tests to serve as \"documentation\" for GlueSQL contributors. At the time we were writing these tests, we didn't anticipate that they could actually become documentation themselves. But we've come to realize that they have extraordinary potential."),(0,o.yg)("h2",{id:"leveraging-chatgpt"},"Leveraging ChatGPT"),(0,o.yg)("p",null,"When we first embarked on writing the User Manual, we were overwhelmed by the sheer volume of content we had to generate. Around the same time, ChatGPT was gaining prominence, and we thought it might be worth trying out, if only to lighten our load slightly."),(0,o.yg)("p",null,"To our surprise, ChatGPT exceeded our expectations. If the test codes were well written, it was capable of automatically crafting an exceptional document based on them, capturing all essential details."),(0,o.yg)("p",null,"After several trials and errors, we settled on the following prompt for document generation. While it's still a challenge to use the same prompt for all documentation, we made minor modifications to suit different situations:"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre"},"I'm creating an SQL database documentation website, and I'd like you to help me with one of the pages that introduces the SQL syntax for GlueSQL.\n\n1. Please provide the response content in the \"markdown\" format, so I can copy and paste it directly. Keep this constraint in mind while writing. \n2. Regardless of the language I use, I need the content written in English. \n3. I will provide some test case code written in the Rust language, which contains SQL examples. Please write the documentation based on these examples, but feel free to change the table names, column names, and data types as needed. Don't include any Rust related content or text in the response. all the response code example should be in plain SQL. \n4. GlueSQL does not have the VARCHAR type. If you want to use that, please use TEXT instead. You don't need to mention this in the response. \n5. Wrap the entire response text using
 and 
tags so I can copy all the content easily. \n\nNow, I'd like you to write the following request: \nSQL Statement - \"INSERT\" \n\nHere's an example test code you can refer to:\n\ntest_case!(insert, async move {\n run!(...\n")),(0,o.yg)("p",null,"Generally, we used the template above, and copied and pasted the test code from our existing test-suite. We leveraged this method to harness our many tests to assist in the creation of the user manual. In the next section, we'll showcase a sample of the documentation generated in this manner. It's quite impressive."),(0,o.yg)("h2",{id:"success-case-automated-user-manual-of-gluesql"},"Success Case: Automated User Manual of GlueSQL"),(0,o.yg)("p",null,"Thanks to ChatGPT, the resulting INSERT document page can be viewed at the following link. It's important to note that we used ChatGPT 4 for this task. Version 3.5 wasn't quite up to the task, and using version 4 was the minimum requirement."),(0,o.yg)("p",null,(0,o.yg)("a",{parentName:"p",href:"https://gluesql.org/docs/dev/sql-syntax/statements/data-manipulation/insert"},"https://gluesql.org/docs/dev/sql-syntax/statements/data-manipulation/insert")),(0,o.yg)("p",null,(0,o.yg)("img",{alt:"INSERT Statement",src:n(2354).A,width:"2203",height:"1739"})),(0,o.yg)("p",null,"The results were quite impressive. ChatGPT neatly categorized the test cases, explained the syntax, outlined constraints, and provided appropriate examples. It didn't stop there; it also skillfully recognized error test cases and incorporated them into the documentation, as shown below."),(0,o.yg)("p",null,(0,o.yg)("img",{alt:"INSERT Statement",src:n(9455).A,width:"1751",height:"353"})),(0,o.yg)("p",null,"Isn't it amazing?"),(0,o.yg)("h2",{id:"future-plans-fully-automating-documentation-generation"},"Future Plans: Fully Automating Documentation Generation"),(0,o.yg)("p",null,"While the current documentation is far from perfect and there are many aspects that can be improved, we see great potential in this approach. We believe it's entirely possible to automate the process of writing this kind of document, and writing in general."),(0,o.yg)("p",null,"In the past, documents like user manuals required a great deal of effort to maintain once they were written. If a document contained real code examples, verifying that the code still worked was often a tedious task. With the ability to automatically generate documentation as we have done here, these issues are no longer problematic."),(0,o.yg)("p",null,"Previously, you would have to write tests and then also document them separately. If you had to support multiple languages, that would be an additional task. With a tool like ChatGPT, you can automate all of this. All a developer has to do is write the tests. This alone can be sufficient. You can generate documents automatically based on the tests. Eventually, we can even support automatically translating these documents into multiple languages."),(0,o.yg)("p",null,"The GlueSQL project repository is currently hosted on GitHub and makes good use of various GitHub Actions. We envision a GitHub Action that automatically regenerates a document corresponding to a test when a user modifies the test and raises a Pull Request. Another GitHub Action could automatically translate updated documents into supported languages and create new Pull Requests. The possibilities are truly endless."),(0,o.yg)("p",null,"Not only will this help with document generation, but it will also provide clear guidelines for writing better test code. If we can automatically generate documents based on written tests, the quality of those documents can serve as an indicator of the quality of the tests themselves. This means that a document automation tool can play the role of a good reviewer for tests. It can greatly reduce the time and effort required for painstakingly reviewing the quality of each test. Developers can also write tests without pressure, evaluate their test code by looking at the generated document, and improve it."),(0,o.yg)("p",null,"Furthermore, multi-language support becomes a breeze. In my personal experience as a software engineer over the past decade, developing various products such as games, web services, and applications, I often needed to support multiple languages. Each time, there was no definite solution. The optimal approach varied depending on the situation, and there were many things to consider when entrusting translations, such as effectively communicating the context of the target service to the translator. Moreover, regularly updating content and having it retranslated into various languages was a very tedious process. While I tried to automate as much as possible by creating various tools, I was never fully satisfied. I believe ChatGPT can completely solve these issues. If there is a need to provide project-specific context, all you need to do is prepare a prompt in advance. Instead of having to rely on and wait for professional translators, we can now entrust this task to ChatGPT, and we only need a few people to review the translated content."),(0,o.yg)("p",null,"We are nearing a world where documentation is no longer a burden for developers."),(0,o.yg)("h2",{id:"conclusion-the-value-of-test-driven-documentation"},"Conclusion: The Value of Test-Driven Documentation"),(0,o.yg)("p",null,"The use of ChatGPT to generate documentation has proven a significant step forward in the GlueSQL user manual creation process. Through test-driven documentation, we've managed to automate a substantial part of the manual creation process, saving time and effort, and increasing accuracy."),(0,o.yg)("p",null,"Moreover, this process has unveiled a new potential for documentation: the possibility of fully automating document generation. We've seen that quality tests can become quality documentation with the help of AI, leading to more efficient workflows and possibly better test code as a result."),(0,o.yg)("p",null,"The journey doesn't stop here. We envision leveraging this capability further to auto-translate our documents into multiple languages, making our product more accessible to a global audience."),(0,o.yg)("p",null,"As we progress, we hope that our experience can inspire other developers to explore and embrace the benefits of AI-generated, test-driven documentation. It's not just about saving time\u2014it's about improving the way we work, communicate, and share knowledge."))}h.isMDXComponent=!0},9455:(e,t,n)=>{n.d(t,{A:()=>a});const a=n.p+"assets/images/blog-test-driven-documentation-insert-errorcase-1be5ced205cee0d2eeb56af1591440ac.jpg"},2354:(e,t,n)=>{n.d(t,{A:()=>a});const a=n.p+"assets/images/blog-test-driven-documentation-insert-7dfbb3a9123d4aa47b845b7dede97dc9.jpg"}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/50818478.556f0b73.js b/docs/0.16.0/assets/js/50818478.556f0b73.js new file mode 100644 index 00000000..1665ef87 --- /dev/null +++ b/docs/0.16.0/assets/js/50818478.556f0b73.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[6088],{5680:(e,t,n)=>{n.d(t,{xA:()=>u,yg:()=>m});var a=n(6540);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function s(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var i=a.createContext({}),p=function(e){var t=a.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},u=function(e){var t=p(e.components);return a.createElement(i.Provider,{value:t},e.children)},c="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},y=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),c=p(n),y=r,m=c["".concat(i,".").concat(y)]||c[y]||d[y]||o;return n?a.createElement(m,s(s({ref:t},u),{},{components:n})):a.createElement(m,s({ref:t},u))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,s=new Array(o);s[0]=y;var l={};for(var i in t)hasOwnProperty.call(t,i)&&(l[i]=t[i]);l.originalType=e,l[c]="string"==typeof e?e:r,s[1]=l;for(var p=2;p{n.r(t),n.d(t,{assets:()=>i,contentTitle:()=>s,default:()=>d,frontMatter:()=>o,metadata:()=>l,toc:()=>p});var a=n(8168),r=(n(6540),n(5680));const o={sidebar_position:11},s="MAP",l={unversionedId:"sql-syntax/data-types/map",id:"sql-syntax/data-types/map",title:"MAP",description:"The MAP data type in GlueSQL is used to store nested key-value pairs, similar to JSON objects. The object keys must be strings, and the values can be any valid data supported by GlueSQL, such as numbers, strings, booleans, null, or even other nested MAP values. Although the input is provided in a JSON object format for convenience, it can store more than just JSON data.",source:"@site/docs/sql-syntax/data-types/map.md",sourceDirName:"sql-syntax/data-types",slug:"/sql-syntax/data-types/map",permalink:"/docs/0.16.0/sql-syntax/data-types/map",draft:!1,tags:[],version:"current",sidebarPosition:11,frontMatter:{sidebar_position:11},sidebar:"autoSidebar",previous:{title:"LIST",permalink:"/docs/0.16.0/sql-syntax/data-types/list"},next:{title:"BYTEA",permalink:"/docs/0.16.0/sql-syntax/data-types/bytea"}},i={},p=[],u={toc:p},c="wrapper";function d(e){let{components:t,...n}=e;return(0,r.yg)(c,(0,a.A)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,r.yg)("h1",{id:"map"},"MAP"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"MAP")," data type in GlueSQL is used to store nested key-value pairs, similar to JSON objects. The object keys must be strings, and the values can be any valid data supported by GlueSQL, such as numbers, strings, booleans, ",(0,r.yg)("inlineCode",{parentName:"p"},"null"),", or even other nested ",(0,r.yg)("inlineCode",{parentName:"p"},"MAP")," values. Although the input is provided in a JSON object format for convenience, it can store more than just JSON data."),(0,r.yg)("p",null,"Here is an example of creating a table with a ",(0,r.yg)("inlineCode",{parentName:"p"},"MAP")," data type:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE MapType (\n id INTEGER,\n nested MAP\n);\n")),(0,r.yg)("p",null,"You can insert data into the table using JSON-like syntax:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},'INSERT INTO MapType VALUES\n (1, \'{"a": true, "b": 2}\'),\n (2, \'{"a": {"foo": "ok", "b": "steak"}, "b": 30}\'),\n (3, \'{"a": {"b": {"c": {"d": 10}}}}\');\n')),(0,r.yg)("p",null,"To access the nested values in a ",(0,r.yg)("inlineCode",{parentName:"p"},"MAP"),", you can use the index operator ",(0,r.yg)("inlineCode",{parentName:"p"},"[]"),":"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT id, nested['a']['foo'] AS foo FROM MapType;\n")),(0,r.yg)("p",null,"This query would return the following result:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre"}," id | foo\n----|-----\n 1 | null\n 2 | ok\n 3 | null\n")),(0,r.yg)("p",null,"You can also perform arithmetic operations on nested values, like this:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT id, nested['a']['b']['c']['d'] * 2 AS good2 FROM MapType;\n")),(0,r.yg)("p",null,"This query would return the following result:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre"}," id | good2\n----|------\n 1 | null\n 2 | null\n 3 | 20\n")),(0,r.yg)("p",null,"If a specified key does not exist in the ",(0,r.yg)("inlineCode",{parentName:"p"},"MAP"),", the result will be ",(0,r.yg)("inlineCode",{parentName:"p"},"null"),"."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/5242ac2d.16055ebb.js b/docs/0.16.0/assets/js/5242ac2d.16055ebb.js new file mode 100644 index 00000000..f67601c3 --- /dev/null +++ b/docs/0.16.0/assets/js/5242ac2d.16055ebb.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[4222],{5680:(e,t,n)=>{n.d(t,{xA:()=>u,yg:()=>m});var r=n(6540);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var i=r.createContext({}),c=function(e){var t=r.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},u=function(e){var t=c(e.components);return r.createElement(i.Provider,{value:t},e.children)},p="mdxType",y={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},g=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,l=e.originalType,i=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=c(n),g=a,m=p["".concat(i,".").concat(g)]||p[g]||y[g]||l;return n?r.createElement(m,o(o({ref:t},u),{},{components:n})):r.createElement(m,o({ref:t},u))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var l=n.length,o=new Array(l);o[0]=g;var s={};for(var i in t)hasOwnProperty.call(t,i)&&(s[i]=t[i]);s.originalType=e,s[p]="string"==typeof e?e:a,o[1]=s;for(var c=2;c{n.r(t),n.d(t,{assets:()=>i,contentTitle:()=>o,default:()=>y,frontMatter:()=>l,metadata:()=>s,toc:()=>c});var r=n(8168),a=(n(6540),n(5680));const l={},o="SQRT",s={unversionedId:"sql-syntax/functions/math/sqrt",id:"sql-syntax/functions/math/sqrt",title:"SQRT",description:"The SQRT function is used to calculate the square root of a number. It takes one argument, which must be of the FLOAT type. The result will also be of the FLOAT type.",source:"@site/docs/sql-syntax/functions/math/sqrt.md",sourceDirName:"sql-syntax/functions/math",slug:"/sql-syntax/functions/math/sqrt",permalink:"/docs/0.16.0/sql-syntax/functions/math/sqrt",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"SIN",permalink:"/docs/0.16.0/sql-syntax/functions/math/sin"},next:{title:"TAN",permalink:"/docs/0.16.0/sql-syntax/functions/math/tan"}},i={},c=[{value:"Syntax",id:"syntax",level:2},{value:"Examples",id:"examples",level:2},{value:"Error Cases",id:"error-cases",level:2}],u={toc:c},p="wrapper";function y(e){let{components:t,...n}=e;return(0,a.yg)(p,(0,r.A)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"sqrt"},"SQRT"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"SQRT")," function is used to calculate the square root of a number. It takes one argument, which must be of the FLOAT type. The result will also be of the FLOAT type."),(0,a.yg)("h2",{id:"syntax"},"Syntax"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SQRT(number)\n")),(0,a.yg)("h2",{id:"examples"},"Examples"),(0,a.yg)("ol",null,(0,a.yg)("li",{parentName:"ol"},"Using the ",(0,a.yg)("inlineCode",{parentName:"li"},"SQRT")," function:")),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT SQRT(2.0) as sqrt_1;\n-- Result: 1.4142135623730951\n")),(0,a.yg)("ol",{start:2},(0,a.yg)("li",{parentName:"ol"},"Using the ",(0,a.yg)("inlineCode",{parentName:"li"},"SQRT")," function with a decimal:")),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT SQRT(0.07) as sqrt_2;\n-- Result: 0.2645751311064591\n")),(0,a.yg)("ol",{start:3},(0,a.yg)("li",{parentName:"ol"},"Using the ",(0,a.yg)("inlineCode",{parentName:"li"},"SQRT")," function with an integer:")),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT SQRT(32) as sqrt_with_int;\n-- Result: 5.656854249492381\n")),(0,a.yg)("ol",{start:4},(0,a.yg)("li",{parentName:"ol"},"Using the ",(0,a.yg)("inlineCode",{parentName:"li"},"SQRT")," function with zero:")),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT SQRT(0) as sqrt_with_zero;\n-- Result: 0.0\n")),(0,a.yg)("ol",{start:5},(0,a.yg)("li",{parentName:"ol"},"Using the ",(0,a.yg)("inlineCode",{parentName:"li"},"SQRT")," function with NULL:")),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT SQRT(NULL) AS sqrt;\n-- Result: NULL\n")),(0,a.yg)("h2",{id:"error-cases"},"Error Cases"),(0,a.yg)("ol",null,(0,a.yg)("li",{parentName:"ol"},"The ",(0,a.yg)("inlineCode",{parentName:"li"},"SQRT")," function requires the argument to be of FLOAT type:")),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT SQRT('string') AS sqrt;\n-- Error: SqrtOnNonNumeric(\"string\")\n")))}y.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/56ccfc32.2dcbb12d.js b/docs/0.16.0/assets/js/56ccfc32.2dcbb12d.js new file mode 100644 index 00000000..9ca5d7cd --- /dev/null +++ b/docs/0.16.0/assets/js/56ccfc32.2dcbb12d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[6098],{5680:(e,n,t)=>{t.d(n,{xA:()=>c,yg:()=>y});var r=t(6540);function a(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function l(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function i(e){for(var n=1;n=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var s=r.createContext({}),u=function(e){var n=r.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},c=function(e){var n=u(e.components);return r.createElement(s.Provider,{value:n},e.children)},p="mdxType",g={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},m=r.forwardRef((function(e,n){var t=e.components,a=e.mdxType,l=e.originalType,s=e.parentName,c=o(e,["components","mdxType","originalType","parentName"]),p=u(t),m=a,y=p["".concat(s,".").concat(m)]||p[m]||g[m]||l;return t?r.createElement(y,i(i({ref:n},c),{},{components:t})):r.createElement(y,i({ref:n},c))}));function y(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var l=t.length,i=new Array(l);i[0]=m;var o={};for(var s in n)hasOwnProperty.call(n,s)&&(o[s]=n[s]);o.originalType=e,o[p]="string"==typeof e?e:a,i[1]=o;for(var u=2;u{t.r(n),t.d(n,{assets:()=>s,contentTitle:()=>i,default:()=>g,frontMatter:()=>l,metadata:()=>o,toc:()=>u});var r=t(8168),a=(t(6540),t(5680));const l={},i="CEIL",o={unversionedId:"sql-syntax/functions/math/ceil",id:"sql-syntax/functions/math/ceil",title:"CEIL",description:"The CEIL function is used to round a number up to the nearest integer value. It takes a single floating-point or integer value as its argument and returns a floating-point value.",source:"@site/docs/sql-syntax/functions/math/ceil.md",sourceDirName:"sql-syntax/functions/math",slug:"/sql-syntax/functions/math/ceil",permalink:"/docs/0.16.0/sql-syntax/functions/math/ceil",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"ATAN",permalink:"/docs/0.16.0/sql-syntax/functions/math/atan"},next:{title:"COS",permalink:"/docs/0.16.0/sql-syntax/functions/math/cos"}},s={},u=[{value:"Syntax",id:"syntax",level:2},{value:"Examples",id:"examples",level:2},{value:"Example 1: Using CEIL function",id:"example-1-using-ceil-function",level:3},{value:"Errors",id:"errors",level:2},{value:"Example 2: Using CEIL with a string argument",id:"example-2-using-ceil-with-a-string-argument",level:3},{value:"Example 3: Using CEIL with a boolean argument",id:"example-3-using-ceil-with-a-boolean-argument",level:3}],c={toc:u},p="wrapper";function g(e){let{components:n,...t}=e;return(0,a.yg)(p,(0,r.A)({},c,t,{components:n,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"ceil"},"CEIL"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"CEIL")," function is used to round a number up to the nearest integer value. It takes a single floating-point or integer value as its argument and returns a floating-point value."),(0,a.yg)("h2",{id:"syntax"},"Syntax"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"CEIL(value)\n")),(0,a.yg)("h2",{id:"examples"},"Examples"),(0,a.yg)("p",null,"Let's consider a table named ",(0,a.yg)("inlineCode",{parentName:"p"},"SingleItem")," with the following schema:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE SingleItem (id INTEGER);\n")),(0,a.yg)("p",null,"Insert a row into the ",(0,a.yg)("inlineCode",{parentName:"p"},"SingleItem")," table:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO SingleItem VALUES (0);\n")),(0,a.yg)("h3",{id:"example-1-using-ceil-function"},"Example 1: Using CEIL function"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT CEIL(0.3) AS ceil1,\nCEIL(-0.8) AS ceil2,\nCEIL(10) AS ceil3,\nCEIL(6.87421) AS ceil4\nFROM SingleItem;\n")),(0,a.yg)("p",null,"Result:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre"},"ceil1 | ceil2 | ceil3 | ceil4\n------+-------+-------+-------\n 1.0 | 0.0 | 10.0 | 7.0\n")),(0,a.yg)("p",null,"Note that the returned values are floating-point numbers, even though they represent integer values."),(0,a.yg)("h2",{id:"errors"},"Errors"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"CEIL")," function expects a floating-point or integer value as its argument. Providing any other type, such as a string or boolean, will result in an error."),(0,a.yg)("h3",{id:"example-2-using-ceil-with-a-string-argument"},"Example 2: Using CEIL with a string argument"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT CEIL('string') AS ceil FROM SingleItem;\n")),(0,a.yg)("p",null,"Error: Function requires a floating-point or integer value."),(0,a.yg)("h3",{id:"example-3-using-ceil-with-a-boolean-argument"},"Example 3: Using CEIL with a boolean argument"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT CEIL(TRUE) AS ceil FROM SingleItem;\n")),(0,a.yg)("p",null,"Error: Function requires a floating-point or integer value."))}g.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/575d1ad6.074a3068.js b/docs/0.16.0/assets/js/575d1ad6.074a3068.js new file mode 100644 index 00000000..c33a6f5b --- /dev/null +++ b/docs/0.16.0/assets/js/575d1ad6.074a3068.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[9700],{1224:e=>{e.exports=JSON.parse('{"blogPosts":[{"id":"release-v0.15","metadata":{"permalink":"/docs/0.16.0/blog/release-v0.15","source":"@site/blog/2023-11-18-release-v0.15.md","title":"Release v0.15","description":"Release Note - v0.15","date":"2023-11-18T00:00:00.000Z","formattedDate":"November 18, 2023","tags":[{"label":"v0.15","permalink":"/docs/0.16.0/blog/tags/v-0-15"},{"label":"release-note","permalink":"/docs/0.16.0/blog/tags/release-note"}],"readingTime":5.93,"hasTruncateMarker":false,"authors":[{"name":"Taehoon Moon","title":"Creator of GlueSQL","url":"https://github.com/panarch","image_url":"https://github.com/panarch.png","imageURL":"https://github.com/panarch.png"}],"frontMatter":{"title":"Release v0.15","description":"Release Note - v0.15","slug":"release-v0.15","authors":[{"name":"Taehoon Moon","title":"Creator of GlueSQL","url":"https://github.com/panarch","image_url":"https://github.com/panarch.png","imageURL":"https://github.com/panarch.png"}],"tags":["v0.15","release-note"]},"nextItem":{"title":"GlueSQL - Revolutionizing Databases by Unifying Query Interfaces","permalink":"/docs/0.16.0/blog/revolutionizing-databases-by-unifying-query-interfaces"}},"content":"## \ud83c\udf0a Breaking Changes\\n\\n### \ud83c\udf40 Python Support\\n- [https://pypi.org/project/gluesql/](https://pypi.org/project/gluesql/)\\n\\n#### Code Samples\\n```python\\nfrom gluesql import Glue, MemoryStorage\\nfrom tabulate import tabulate\\n\\ndb = Glue(MemoryStorage())\\n\\nsql = \\"\\"\\"\\n SELECT\\n u.name as user,\\n d.name as device\\n FROM User u\\n JOIN Device d ON u.id = d.userId\\n\\"\\"\\".strip().replace(\\n \\" \\", \\"\\"\\n)\\n\\nresult = db.query(sql)\\nrows = result[0].get(\\"rows\\")\\nprint(f\\"\\\\n[Query]\\\\n{sql}\\")\\nprint(tabulate(rows, headers=\\"keys\\", showindex=True, tablefmt=\\"simple_outline\\"))\\n```\\n\\n- feat: Implement Python Binding [@jopemachine](https://github.com/jopemachine) ([#1357](https://github.com/gluesql/gluesql/pull/1357))\\n\\n### \ud83c\udf40 Redis Storage\\n\\n- Feature: redis storage [@gurugio](https://github.com/gurugio) ([#1396](https://github.com/gluesql/gluesql/pull/1396))\\n\\n### \ud83c\udf40 CSV Storage\\n\\n- Add CsvStorage support to CLI \\\\& Rust package [@panarch](https://github.com/panarch) ([#1437](https://github.com/gluesql/gluesql/pull/1437))\\n- Implement CSV Storage, [@panarch](https://github.com/panarch) ([#1280](https://github.com/gluesql/gluesql/pull/1280))\\n\\n### \ud83c\udf40 More operators and functions\\n\\n- feat: add index\\\\_by node [@seonghun-dev](https://github.com/seonghun-dev) ([#1355](https://github.com/gluesql/gluesql/pull/1355))\\n- Implement DEDUP function [@jinlee0](https://github.com/jinlee0) ([#1430](https://github.com/gluesql/gluesql/pull/1430))\\n- Bitwise Shift Right Operator Implementation [@2-NOW](https://github.com/2-NOW) ([#1394](https://github.com/gluesql/gluesql/pull/1394))\\n- feat: implement ast\\\\_builder for values function [@tgsong827](https://github.com/tgsong827) ([#1375](https://github.com/gluesql/gluesql/pull/1375))\\n- Implement `ADD_MONTH` function [@kite707](https://github.com/kite707) ([#1341](https://github.com/gluesql/gluesql/pull/1341))\\n- Implement `SPLICE` function [@jinlee0](https://github.com/jinlee0) ([#1371](https://github.com/gluesql/gluesql/pull/1371))\\n- Implement `SLICE` function [@Kwontaehwon](https://github.com/Kwontaehwon) ([#1340](https://github.com/gluesql/gluesql/pull/1340))\\n- Implement entries in ast builder [@2-NOW](https://github.com/2-NOW) ([#1364](https://github.com/gluesql/gluesql/pull/1364))\\n- Implement GREATEST function [@TheMan1697](https://github.com/TheMan1697) ([#1312](https://github.com/gluesql/gluesql/pull/1312))\\n- Implement bitwise-not operator (~) in ast builder [@gurugio](https://github.com/gurugio) ([#1366](https://github.com/gluesql/gluesql/pull/1366))\\n- Implement COALESCE function [@cake-monotone](https://github.com/cake-monotone) ([#1333](https://github.com/gluesql/gluesql/pull/1333))\\n- feat: Implement select without table function in ast\\\\_builder [@ding-co](https://github.com/ding-co) ([#1365](https://github.com/gluesql/gluesql/pull/1365))\\n- Add ExprWithAliasNode to ast builder [@julia-ing](https://github.com/julia-ing) ([#1359](https://github.com/gluesql/gluesql/pull/1359))\\n- feat: Implement take function in ast\\\\_builder [@ding-co](https://github.com/ding-co) ([#1346](https://github.com/gluesql/gluesql/pull/1346))\\n- Implement last\\\\_day function in ast\\\\_builder [@cjy13753](https://github.com/cjy13753) ([#1344](https://github.com/gluesql/gluesql/pull/1344))\\n- Implement LAST\\\\_DAY function [#1315](https://github.com/gluesql/gluesql/pull/1315) [@cjy13753](https://github.com/cjy13753) ([#1323](https://github.com/gluesql/gluesql/pull/1323))\\n- Implement ast\\\\_builder for is\\\\_empty function [@julia-ing](https://github.com/julia-ing) ([#1337](https://github.com/gluesql/gluesql/pull/1337))\\n- Implement `ast_builder` for skip function [@cl-kim](https://github.com/cl-kim) ([#1334](https://github.com/gluesql/gluesql/pull/1334))\\n- Implement ENTRIES function [@2-NOW](https://github.com/2-NOW) ([#1315](https://github.com/gluesql/gluesql/pull/1315))\\n- Feature/operator bit not [@gurugio](https://github.com/gurugio) ([#1321](https://github.com/gluesql/gluesql/pull/1321))\\n- Implement Skip function [@cl-kim](https://github.com/cl-kim) ([#1325](https://github.com/gluesql/gluesql/pull/1325))\\n- Implement VALUES function for Map type [@tgsong827](https://github.com/tgsong827) ([#1288](https://github.com/gluesql/gluesql/pull/1288))\\n- Feat: impl bitwise-and operation [@jinlee0](https://github.com/jinlee0) ([#1281](https://github.com/gluesql/gluesql/pull/1281))\\n- Implement BIT\\\\_SHIFT\\\\_LEFT operation [@codernineteen](https://github.com/codernineteen) ([#1286](https://github.com/gluesql/gluesql/pull/1286))\\n- implement `SORT` function [@Jaehui-Lee](https://github.com/Jaehui-Lee) ([#1300](https://github.com/gluesql/gluesql/pull/1300))\\n- feat: Implement `LENGTH` function [@jopemachine](https://github.com/jopemachine) ([#1298](https://github.com/gluesql/gluesql/pull/1298))\\n- [Function] Implement TAKE function [@ding-co](https://github.com/ding-co) ([#1283](https://github.com/gluesql/gluesql/pull/1283))\\n- feat: implement `ast_builder` for replace function [@ChobobDev](https://github.com/ChobobDev) ([#1275](https://github.com/gluesql/gluesql/pull/1275))\\n- feat: implement IS\\\\_EMPTY function [@julia-ing](https://github.com/julia-ing) ([#1282](https://github.com/gluesql/gluesql/pull/1282))\\n- [Function] Implement REPLACE function [@ChobobDev](https://github.com/ChobobDev) ([#1266](https://github.com/gluesql/gluesql/pull/1266))\\n- Implement MD5 Function [@seonghun-dev](https://github.com/seonghun-dev) ([#1242](https://github.com/gluesql/gluesql/pull/1242))\\n- [AST Builder] Implement ascii, chr function in ast [@seonghun-dev](https://github.com/seonghun-dev) ([#1244](https://github.com/gluesql/gluesql/pull/1244))\\n- [AST Builder] Implement Geometic Point Type and Geometric Function in AST Builder [@seonghun-dev](https://github.com/seonghun-dev) ([#1222](https://github.com/gluesql/gluesql/pull/1222))\\n\\n## \ud83d\ude80 Features\\n\\n- feat: implement `select` iterator utility function [@ever0de](https://github.com/ever0de) ([#1429](https://github.com/gluesql/gluesql/pull/1429))\\n\\n## \ud83c\udf1f Improvements\\n\\n- Fix parsing of BigDecimal literals with zero fraction part as floats, not integer [@zmrdltl](https://github.com/zmrdltl) ([#1416](https://github.com/gluesql/gluesql/pull/1416))\\n- Update docs/ast-builder padding.md code block lang keyword, [@panarch](https://github.com/panarch) ([#1436](https://github.com/gluesql/gluesql/pull/1436))\\n- Support StoreMut trait to Optional [@seonghun-dev](https://github.com/seonghun-dev) ([#1435](https://github.com/gluesql/gluesql/pull/1435))\\n- docs: write docmentation for padding [@devgony](https://github.com/devgony) ([#1434](https://github.com/gluesql/gluesql/pull/1434))\\n- test: add test cases for astb-padding [@devgony](https://github.com/devgony) ([#1433](https://github.com/gluesql/gluesql/pull/1433))\\n- Upgrade to chrono v0.4.31 and adjust millisecond value in Timestamp Creation [@zmrdltl](https://github.com/zmrdltl) ([#1427](https://github.com/gluesql/gluesql/pull/1427))\\n- Remove unnecessary comments in evalaute/function.rs [@panarch](https://github.com/panarch) ([#1431](https://github.com/gluesql/gluesql/pull/1431))\\n- write docmentation for character\\\\_conversion [@devgony](https://github.com/devgony) ([#1428](https://github.com/gluesql/gluesql/pull/1428))\\n- docs: Add `SLICE` function doc [@fregataa](https://github.com/fregataa) ([#1425](https://github.com/gluesql/gluesql/pull/1425))\\n- test: add cases to character\\\\_conversion [@devgony](https://github.com/devgony) ([#1424](https://github.com/gluesql/gluesql/pull/1424))\\n- docs:Add doc about SPLICE function [@jinlee0](https://github.com/jinlee0) ([#1423](https://github.com/gluesql/gluesql/pull/1423))\\n- Change store RowIter type from Iterator to Stream [@panarch](https://github.com/panarch) ([#1419](https://github.com/gluesql/gluesql/pull/1419))\\n- Reflect Deprecation of `from_utc` in Crate `chrono` [@zmrdltl](https://github.com/zmrdltl) ([#1415](https://github.com/gluesql/gluesql/pull/1415))\\n- Remove eval\\\\_to\\\\_{int|float..} macro uses in core/../evaluate/function.rs, [@panarch](https://github.com/panarch) ([#1361](https://github.com/gluesql/gluesql/pull/1361))\\n- test: write example for ast builder [@daengdaengLee](https://github.com/daengdaengLee) ([#1259](https://github.com/gluesql/gluesql/pull/1259))\\n- Fix merge conflict in data/value/mod.rs [@panarch](https://github.com/panarch) ([#1406](https://github.com/gluesql/gluesql/pull/1406))\\n- chore: implement `ConvertError`, [@ever0de](https://github.com/ever0de) ([#1401](https://github.com/gluesql/gluesql/pull/1401))\\n- refactor: remove implementation of from Value trait for Evaluated [@tgsong827](https://github.com/tgsong827) ([#1399](https://github.com/gluesql/gluesql/pull/1399))\\n- refactor: update function module\'s namespacing in ast\\\\_builder [@tgsong827](https://github.com/tgsong827) ([#1398](https://github.com/gluesql/gluesql/pull/1398))\\n- chore: remove `Result` from `ast_builder::transaction` return type [@ever0de](https://github.com/ever0de) ([#1404](https://github.com/gluesql/gluesql/pull/1404))\\n- chore: bump rust version to 1.72 [@ever0de](https://github.com/ever0de) ([#1388](https://github.com/gluesql/gluesql/pull/1388))\\n- chore: add example of convert from payload to custom struct [@ever0de](https://github.com/ever0de) ([#1379](https://github.com/gluesql/gluesql/pull/1379))\\n- Update Chrono version to 0.4.26, [@panarch](https://github.com/panarch) ([#1374](https://github.com/gluesql/gluesql/pull/1374))\\n- Update test-suite Tester::run to return Payload, [@panarch](https://github.com/panarch) ([#1373](https://github.com/gluesql/gluesql/pull/1373))\\n- Remove .unwrap() uses in test-suite/ test codes, [@panarch](https://github.com/panarch) ([#1372](https://github.com/gluesql/gluesql/pull/1372))\\n- Replace run!, test! and count! macros in test-suite to Tester methods, [@panarch](https://github.com/panarch) ([#1368](https://github.com/gluesql/gluesql/pull/1368))\\n- Update coverage.yml gh-action to ignore await only lines, [@panarch](https://github.com/panarch) ([#1370](https://github.com/gluesql/gluesql/pull/1370))\\n- Apply pretty\\\\_assertions::assert\\\\_eq! to core/ ast\\\\_builder unit tests [@panarch](https://github.com/panarch) ([#1369](https://github.com/gluesql/gluesql/pull/1369))\\n- Simplify value evaluate cmp with literal [@panarch](https://github.com/panarch) ([#1353](https://github.com/gluesql/gluesql/pull/1353))\\n- Update gh-action author assign - add zmrdltl to reviewers [@panarch](https://github.com/panarch) ([#1342](https://github.com/gluesql/gluesql/pull/1342))\\n- Refactor GCD and LCM functions [@cake-monotone](https://github.com/cake-monotone) ([#1331](https://github.com/gluesql/gluesql/pull/1331))\\n- Refactor write\\\\_rows [@devgony](https://github.com/devgony) ([#1319](https://github.com/gluesql/gluesql/pull/1319))\\n- Js pkg wasm pack build not to generate readme and packagejson [@panarch](https://github.com/panarch) ([#1327](https://github.com/gluesql/gluesql/pull/1327))\\n- Update pkg/javascript dist directories to use dist\\\\_web/ and dist\\\\_node\u2026 [@panarch](https://github.com/panarch) ([#1326](https://github.com/gluesql/gluesql/pull/1326))\\n- Upgrade bigdecimal to 0.4.1, sqlparser to 0.36.1 [@jinlee0](https://github.com/jinlee0) ([#1322](https://github.com/gluesql/gluesql/pull/1322))\\n- Update wasm-pack-action version to 0.4.0, [@panarch](https://github.com/panarch) ([#1316](https://github.com/gluesql/gluesql/pull/1316))\\n- Update JavaScript package load\\\\_indexeddb method to get namespace as a\u2026 [@panarch](https://github.com/panarch) ([#1320](https://github.com/gluesql/gluesql/pull/1320))\\n- Upgrade sqlparser-rs version to 0.35, [@panarch](https://github.com/panarch) ([#1292](https://github.com/gluesql/gluesql/pull/1292))\\n- Remove unused error variant in JsonStorage [@panarch](https://github.com/panarch) ([#1278](https://github.com/gluesql/gluesql/pull/1278))\\n- Implement CAST text literal or value to MAP or LIST, [@panarch](https://github.com/panarch) ([#1267](https://github.com/gluesql/gluesql/pull/1267))\\n- Simplity JsonStorage Store::fetch\\\\_all\\\\_schemas codes, [@panarch](https://github.com/panarch) ([#1264](https://github.com/gluesql/gluesql/pull/1264))\\n- Change console.log in gluesql.js -> console.debug [@parkma99](https://github.com/parkma99) ([#1256](https://github.com/gluesql/gluesql/pull/1256))\\n- Replace `actions-rs/toolchain` with `dtolnay/rust-toolchain` [@jongwooo](https://github.com/jongwooo) ([#1251](https://github.com/gluesql/gluesql/pull/1251))\\n- ci: Automatically assign a PR to its author [@rapsealk](https://github.com/rapsealk) ([#1253](https://github.com/gluesql/gluesql/pull/1253))\\n- Remove sync methods in core/ Glue struct, [@panarch](https://github.com/panarch) ([#1247](https://github.com/gluesql/gluesql/pull/1247))\\n- Remove test function in test-suite tester, [@panarch](https://github.com/panarch) ([#1246](https://github.com/gluesql/gluesql/pull/1246))\\n- fix: allow interval cast-related functions to accept only literals instead of evaluations [@ever0de](https://github.com/ever0de) ([#1238](https://github.com/gluesql/gluesql/pull/1238))\\n- Split custom Partial{Eq|Ord} impl of Value \\\\& Literal into evaluate\\\\_{eq|cmp} [@panarch](https://github.com/panarch) ([#1233](https://github.com/gluesql/gluesql/pull/1233))\\n- Improve example codes formatting [@jopemachine](https://github.com/jopemachine) ([#1235](https://github.com/gluesql/gluesql/pull/1235))\\n- feat: fmt list and map [@Mehrbod2002](https://github.com/Mehrbod2002) ([#1226](https://github.com/gluesql/gluesql/pull/1226))\\n- Update README.md - add blog article links [@panarch](https://github.com/panarch) ([#1232](https://github.com/gluesql/gluesql/pull/1232))\\n- Write the blog article - revolutionizing databases by unifying the qu\u2026 [@panarch](https://github.com/panarch) ([#1231](https://github.com/gluesql/gluesql/pull/1231))\\n- Write the blog article - test driven documentation [@panarch](https://github.com/panarch) ([#1229](https://github.com/gluesql/gluesql/pull/1229))\\n- Write the blog article - breaking the boundary between sql and nosql \u2026 [@panarch](https://github.com/panarch) ([#1228](https://github.com/gluesql/gluesql/pull/1228))\\n- Add test and doc for ast-builder::statements::querying::data-aggregation [@devgony](https://github.com/devgony) ([#1224](https://github.com/gluesql/gluesql/pull/1224))\\n\\n## \ud83d\udc1b Bug Fixes\\n\\n- fix: Literal comparison with BinaryOperator [@ding-co](https://github.com/ding-co) ([#1397](https://github.com/gluesql/gluesql/pull/1397))\\n- fix: update Key.cmp to compare a type with other type [@tgsong827](https://github.com/tgsong827) ([#1367](https://github.com/gluesql/gluesql/pull/1367))\\n- Fix Value::evaluate\\\\_cmp\\\\_with\\\\_literal between Decimal and Literal::Num\u2026 [@panarch](https://github.com/panarch) ([#1352](https://github.com/gluesql/gluesql/pull/1352))\\n- Fix spool on `tabular off` and `SelectMap` [@devgony](https://github.com/devgony) ([#1314](https://github.com/gluesql/gluesql/pull/1314))\\n- Update auto-assign-action to be triggered on PR open from fork repos [@panarch](https://github.com/panarch) ([#1313](https://github.com/gluesql/gluesql/pull/1313))\\n- Fix Scala Subquery should contain only 1 column [@ChobobDev](https://github.com/ChobobDev) ([#1284](https://github.com/gluesql/gluesql/pull/1284))\\n- Wrap config path by quotes in auto-author-assign.yml [@panarch](https://github.com/panarch) ([#1258](https://github.com/gluesql/gluesql/pull/1258))\\n- Apply word-wrap to docs/ article h1 [@panarch](https://github.com/panarch) ([#1230](https://github.com/gluesql/gluesql/pull/1230))\\n- Fix docusaurus.config.js themeConfig handler [@panarch](https://github.com/panarch) ([#1225](https://github.com/gluesql/gluesql/pull/1225))\\n\\n## \ud83d\udc4f New Contributors\\n* [@Mehrbod2002](https://github.com/Mehrbod2002) made their first contribution in https://github.com/gluesql/gluesql/pull/1226\\n* [@jopemachine](https://github.com/jopemachine) made their first contribution in https://github.com/gluesql/gluesql/pull/1235\\n* [@rapsealk](https://github.com/rapsealk) made their first contribution in https://github.com/gluesql/gluesql/pull/1253\\n* [@parkma99](https://github.com/parkma99) made their first contribution in https://github.com/gluesql/gluesql/pull/1256\\n* [@julia-ing](https://github.com/julia-ing) made their first contribution in https://github.com/gluesql/gluesql/pull/1282\\n* [@ding-co](https://github.com/ding-co) made their first contribution in https://github.com/gluesql/gluesql/pull/1283\\n* [@Jaehui-Lee](https://github.com/Jaehui-Lee) made their first contribution in https://github.com/gluesql/gluesql/pull/1300\\n* [@jinlee0](https://github.com/jinlee0) made their first contribution in https://github.com/gluesql/gluesql/pull/1322\\n* [@codernineteen](https://github.com/codernineteen) made their first contribution in https://github.com/gluesql/gluesql/pull/1286\\n* [@tgsong827](https://github.com/tgsong827) made their first contribution in https://github.com/gluesql/gluesql/pull/1288\\n* [@cl-kim](https://github.com/cl-kim) made their first contribution in https://github.com/gluesql/gluesql/pull/1325\\n* [@gurugio](https://github.com/gurugio) made their first contribution in https://github.com/gluesql/gluesql/pull/1321\\n* [@2-NOW](https://github.com/2-NOW) made their first contribution in https://github.com/gluesql/gluesql/pull/1315\\n* [@cake-monotone](https://github.com/cake-monotone) made their first contribution in https://github.com/gluesql/gluesql/pull/1331\\n* [@cjy13753](https://github.com/cjy13753) made their first contribution in https://github.com/gluesql/gluesql/pull/1323\\n* [@TheMan1697](https://github.com/TheMan1697) made their first contribution in https://github.com/gluesql/gluesql/pull/1312\\n* [@Kwontaehwon](https://github.com/Kwontaehwon) made their first contribution in https://github.com/gluesql/gluesql/pull/1340\\n* [@kite707](https://github.com/kite707) made their first contribution in https://github.com/gluesql/gluesql/pull/1341\\n* [@daengdaengLee](https://github.com/daengdaengLee) made their first contribution in https://github.com/gluesql/gluesql/pull/1259\\n* [@fregataa](https://github.com/fregataa) made their first contribution in https://github.com/gluesql/gluesql/pull/1425\\n\\n**Full Changelog**: https://github.com/gluesql/gluesql/compare/v0.14.0...v0.15.0"},{"id":"revolutionizing-databases-by-unifying-query-interfaces","metadata":{"permalink":"/docs/0.16.0/blog/revolutionizing-databases-by-unifying-query-interfaces","source":"@site/blog/2023-05-30-revolutionizing-databases-by-unifying-query-interfaces.md","title":"GlueSQL - Revolutionizing Databases by Unifying Query Interfaces","description":"GlueSQL - Revolutionizing Databases by Unifying Query Interfaces","date":"2023-05-30T00:00:00.000Z","formattedDate":"May 30, 2023","tags":[{"label":"gluesql","permalink":"/docs/0.16.0/blog/tags/gluesql"},{"label":"query-interface","permalink":"/docs/0.16.0/blog/tags/query-interface"},{"label":"database","permalink":"/docs/0.16.0/blog/tags/database"},{"label":"proposal","permalink":"/docs/0.16.0/blog/tags/proposal"}],"readingTime":13.07,"hasTruncateMarker":false,"authors":[{"name":"Taehoon Moon","title":"Creator of GlueSQL","url":"https://github.com/panarch","image_url":"https://github.com/panarch.png","imageURL":"https://github.com/panarch.png"}],"frontMatter":{"title":"GlueSQL - Revolutionizing Databases by Unifying Query Interfaces","description":"GlueSQL - Revolutionizing Databases by Unifying Query Interfaces","slug":"revolutionizing-databases-by-unifying-query-interfaces","authors":[{"name":"Taehoon Moon","title":"Creator of GlueSQL","url":"https://github.com/panarch","image_url":"https://github.com/panarch.png","imageURL":"https://github.com/panarch.png"}],"tags":["gluesql","query-interface","database","proposal"]},"prevItem":{"title":"Release v0.15","permalink":"/docs/0.16.0/blog/release-v0.15"},"nextItem":{"title":"Test-Driven Documentation - Automating User Manual Creation in GlueSQL","permalink":"/docs/0.16.0/blog/test-driven-documentation"}},"content":"## Introduction\\nGlueSQL is a versatile database project designed for exceptional portability across a broad range of environments, from embedded systems and servers to web and mobile platforms. The core goal is to support diverse storage environments and manage various data types with a standard SQL approach.\\n\\nImagine handling files like CSV, JSONL, and Parquet, or transforming key-value or NoSQL databases such as RocksDB, Redis, and MongoDB into SQL-supporting databases\u2014all feasible with GlueSQL. It can also operate with storages supported in web browsers.\\n\\nGlueSQL\'s essential feature is providing a management layer for these diverse storage scenarios without requiring data migration. The broader aim is to facilitate portability of GlueSQL to any environment supporting read or read-write operations. This extends to APIs like GitHub, or messengers like Discord or Slack.\\n\\nGlueSQL supports both structured and unstructured data and is written in Rust for compatibility with various environments. While portability is its core value, the emphasis is on creating an intuitive, comfortable development environment for easy custom storage implementation.\\n\\nUltimately, GlueSQL aims to significantly reduce the cost, time, and complexity of developing new databases. By leveraging GlueSQL for the parser, planner, and execution layer, developers can focus on creating specific storage implementations, leading to a more convenient query interface like SQL for many environments.\\n\\n## The Problem: Why Reinvent the Database?\\nDespite the numerous database implementations that currently exist, the emergence of new databases continues. The primary reason behind this trend is our need for databases for a broad spectrum of distinct purposes. For instance, new databases are surfacing that are specifically optimized for Large Language Models (LLMs) like ChatGPT. The range is wide and diverse, encompassing embedded databases, OLAP for data analysis, OLTP databases optimized for online transactions, databases specialized for time-series data processing, and many more.\\n\\nWith such varied requirements, we find ourselves in constant need of fresh databases. However, constructing a database from scratch is a monumental task. It necessitates defining a query interface for handling the database and implementing a corresponding parser. Moreover, a separate execution layer for running operations must be built. Also, the planning layer, which is responsible for devising execution strategies, is a vital aspect of this process. Let\'s not forget about the critical storage layer that physically reads and stores the data. In a nutshell, there\'s a daunting amount of work involved in developing a new database.\\n\\nGiven these circumstances, it\'s understandable why numerous emerging databases resort to high pricing structures\u2014they need immediate revenue to offset continuous development costs.\\n\\nBut the story doesn\'t end here. Query interfaces like SQL are indeed useful for serious tasks, but they also provide excellent utility for handling simple log files such as CSV, JSONL, Parquet, and even for utilizing REST APIs for various applications. The issue arises when a complex query interface needs to be provided even for these lighter storage requirements\u2014it necessitates a development process almost identical to building a sophisticated database. Implementing an entire parser and execution layer just to add SQL support to an existing service can seem like an excessive burden.\\n\\nWhether it\'s a simple storage environment or a serious task, the key lies in the storage layer, which involves the actual reading and storing of data. So, what if developers focused on implementing these storage mechanisms while the remaining parts could be handled using existing libraries? This is the role that GlueSQL aspires to play.\\n\\n\\n## The Vision of GlueSQL\\nThe GlueSQL project aims to offer a unified query interface for various environments. The goal is to allow anyone to port and use SQL and GlueSQL\'s proprietary query builder, the AST Builder, in any desired environment. This could range from key-value databases, serious NoSQL databases, log files, and even REST API services. Essentially, if a service supports reading or read-writing data, regardless of the data type, it can readily support a complex query interface via GlueSQL.\\n\\nPresently, the GlueSQL project itself directly supports a few storage types as reference storages. These include in-memory storage for non-persistent data handling, sled storage, which is a key-value database written in Rust, JSON storage for handling JSON and JSONL files, and a storage that ports SQL to the web browser\'s IndexedDB. While the GlueSQL Team is primarily developing these, the aim is to allow anyone to create such custom storages for a wide array of purposes, thus enabling them to assemble the database of their choosing.\\n\\nImagine using GlueSQL\'s SQL and AST Builder everywhere, with the simple method of swapping out storages to operate in diverse settings. It could significantly reduce software development costs. Developers wouldn\'t need to learn the different usage methods for each database. Instead, they could focus solely on implementing business logic using the same interface.\\n\\nOur vision is to reduce database development costs by 10 times, or even more than 20 times. We aim to gather diverse database creators under the GlueSQL banner, making it the go-to solution for cost-effective database development.\\n\\n\\n## Benefits to Database Users: Unifying Query Interfaces, Streamlining Software Development, and Reducing Costs\\nFrom the perspective of the users who engage with databases, there has always been the burden of learning different interfaces to interact with each database. The approach required to work with Redis is different from that necessary for MongoDB. Likewise, handling SQL databases necessitates using SQL. Although SQL databases generally use a common SQL, the SQL they support can considerably vary when examined in detail.\\n\\nNaturally, there are legitimate reasons for such differences. Each database focuses on different areas, and to cater to specialized functionalities, they incorporate dedicated interface mechanisms. However, not all application development needs to utilize these database-specific core special functionalities.\\n\\nLet\'s look at a couple of examples:\\n\\nSuppose you\'re developing a back-end application that uses MySQL as the database and Redis for caching. Due to the vast differences in handling SQL databases and Redis, you would have to develop using different methods when storing data.\\n\\nHere\'s another scenario:\\nImagine you\'re implementing a data migration pipeline between various databases and log files. Let\'s say you\'re transferring Parquet to Redis or MongoDB. In this case, you would need to convert data using different methods for each, all of which would be a cumbersome process.\\n\\nIn both of the above examples, GlueSQL can directly address and solve the issues. It offers the convenience of a uniform query interface to deal with these matters. In certain scenarios, even the construction of a data pipeline can potentially be solved with a single SQL query, thanks to GlueSQL.\\n\\n\\n## Benefits to Database Developers: Drastically Lowering Development Costs and Simplifying the Creation of Purpose-Built Databases\\nIf you want to support SQL in the desired environment, using GlueSQL essentially requires you to implement an interface for Storage. There\'s no need to support all functionalities from the beginning. You can start lightly, choosing and implementing storage features suitable for the environment you want to create. To facilitate this, GlueSQL also provides a library in the form of a test suite to easily validate the storage you\'ve implemented.\\n\\nLowering development costs in this way will enable a broader range of developers to support the GlueSQL query interface. As more developers join, a significant synergy can be generated. Designing a query interface from scratch involves a great deal of work, including planning and supporting the interface for different target programming languages.\\n\\nHowever, despite all this hard work, it is not easy to attract database users accustomed to different methods.\\n\\nConsider that the SQL and AST Builder provided by GlueSQL are already securing numerous users. This eliminates the need for efforts to promote a newly planned query interface. Over the years, many new databases have emphasized compatibility with PostgreSQL or MySQL for similar reasons. As GlueSQL places a strong emphasis on portability in its query interface planning, it allows for more flexible configuration according to the desired situation. Through the AST Builder, it also eliminates the cost of porting to different languages.\\n\\nFor many database developers, using GlueSQL can be an optimal choice, as it can save costs and quickly secure users.\\n\\nLet me mention one more thing: what\'s convenient for humans... could be applied to AI as well. Rather than making AI write automation code using different databases, providing a common query interface can be much more efficient.\\n\\n\\n## The Future with GlueSQL\\nGlueSQL has been and will continue to improve and develop new features to enable portability in various environments. Thanks to the schemaless data support added last year, it is now possible to handle both structured data with schema and unstructured data like JSON simultaneously. This has significantly increased the range of storage environments that can be supported.\\n\\nOne of the key features added last year was the AST Builder. This feature allowed us to escape the confines of SQL and provide an interface for comfortably handling data in the programming languages used for development.\\n\\nOf course, improving existing features is extremely important, and there are many new features to be added. As a major development plan this year, we aim to develop features to effectively attach GlueSQL to NoSQL databases with their own planners and execution layers. The GlueSQL query planner, currently at a basic level, will see significant changes this year. With the expansion of this planner, not only NoSQL databases but also other SQL databases could be supported without sacrificing performance using GlueSQL.\\n\\nThe synergy that arises from the combination of different databases is a significant bonus in this process.\\n\\n\\n## The Journey of the GlueSQL Team\\nThe GlueSQL project was first conceived in the fall of 2019, and since then we have been developing it continuously. Personally, I have created various products in a variety of environments, including game development, backend server, and frontend development over the past decade. The experience gained through this process was a major motivation to start the GlueSQL project.\\n\\nTo put it grandly, the inconveniences felt while using different databases in various environments were a major motivation, wouldn\'t you say?\\n\\nThe start was actually a bit simple. Around 2019, I was mainly doing web front-end development. However, the lack of a structured database for state management and internal data processing made it very uncomfortable, especially since I couldn\'t use SQL databases and the like. So I started to lightly create an SQL database that could run on a web browser. Also, I wanted to use Rust, but after failing to introduce it at the company I was working for at the time, I decided to use it in my own project.\\n\\nBut as I started developing, my dreams grew significantly. Beyond a SQL database that simply operates on a web browser, I started envisioning a database that fits the name \\"Glue\\", one that can easily be ported to various environments, and I continue that journey to this day.\\n\\nWhether I took the database project too lightly, or because the features I wanted kept increasing, the content to be developed kept expanding. As a result, I ended up investing full time in the GlueSQL project development for over three years. For a year in between, I even juggled full-time software engineering work alongside GlueSQL development. Currently, I\'m back to developing the GlueSQL project full time, alongside various part-time contributors.\\n\\nNow, we\'re getting very close to the starting point of the picture I wanted to create through GlueSQL, and thankfully, with contributors joining me, I am not alone.\\n\\n\\n## The Sustainability and Business Aspect of GlueSQL\\nI believe that what we create through GlueSQL will make a great contribution to the world and make many software engineers happy. This gives me immense strength to continue developing even in difficult situations. However, we cannot accomplish everything with pure passion alone. As much as the GlueSQL project can make a significant contribution, I also see it as holding great business value.\\n\\nThe business strategy of GlueSQL may be somewhat different from other databases. We distribute the project itself as open source under the Apache-2.0 license, so that anyone can use it fully, and we do not consider pricing methods such as restricting features to the storages we support. In fact, if there is any player who can do it better, there\'s no way to prevent them from taking the GlueSQL project and making it their own.\\n\\nBut we believe that GlueSQL has great potential in this regard. Anyone can participate and they are free to distribute their own storage in the way they want, whether it\'s open source, private, or commercial. This eliminates the need to create something to replace the GlueSQL project. We aim to prevent the need to recreate the wheel that we provide using GlueSQL.\\n\\nMoreover, our GlueSQL team seeks to continually expand our group of developers and companies working with us. During this development process, while they can certainly implement everything on their own, there is also no reason not to collaborate with our GlueSQL Team, especially for databases like NoSQL that have their own planners and execution layers. If you have a REST API and want to enhance convenience through SQL support, you can do it yourself or you can collaborate with us.\\n\\nIn addition, for some storages, we can also participate as players in the same position as other custom storage developers. We plan to expand the GlueSQL ecosystem in various ways, such as technical support and storage development.\\n\\nWe are finally ready to provide GlueSQL to users at the production level. We are accelerating the development of GlueSQL. If you are a company interested in storage development like SQL support, or if you resonate with our vision and want to join us, please contact us at taehoon@gluesql.com.\\n\\n\\n## Conclusion\\nThe continued emergence of new databases is driven by the demand for diverse and specialized databases, such as those optimized for Large Language Models (LLMs) and databases catering to unique requirements, like embedded databases, OLAP, OLTP, and time-series data processing. However, developing a new database from scratch is a significant undertaking, requiring extensive work, which often results in high costs.\\n\\nGlueSQL presents a solution to this challenge by providing a unified query interface that can be ported across various environments, from key-value databases, NoSQL databases, log files, to REST APIs. It allows anyone to create custom storages, reducing the need for developers to build entirely new databases and to learn different usage methods for each database. Instead, they can focus on implementing their business logic using the same interface.\\n\\nFrom a user perspective, GlueSQL offers the convenience of a unified query interface, easing the burden of learning different interfaces for each database. This simplification of interface use can also extend to AI, potentially enhancing the efficiency of AI automation.\\n\\nGlueSQL\'s development plan includes significant enhancements to its query planner and aims to enable effective attachment of GlueSQL to NoSQL databases. The synergy of combining different databases is a valuable bonus in this process.\\n\\nSince its inception in the fall of 2019, the GlueSQL team has continuously developed the project, driven by the desire to mitigate the inconveniences encountered while using different databases in various environments. The journey has been a rewarding one, with the GlueSQL project now at a point where it closely resembles the envisioned product.\\n\\nGlueSQL, distributed under the Apache-2.0 license, is free for anyone to use and adapt. While the GlueSQL team welcomes collaboration with other developers and companies, they also see significant potential for the project as a business venture. The team is working to expand the GlueSQL ecosystem through a variety of initiatives, including technical support and storage development.\\n\\nWith GlueSQL now sufficiently prepared for practical applications, the team invites companies interested in storage development or those who share their vision to join them in their journey of revolutionizing database development."},{"id":"test-driven-documentation","metadata":{"permalink":"/docs/0.16.0/blog/test-driven-documentation","source":"@site/blog/2023-05-30-test-driven-documentation.md","title":"Test-Driven Documentation - Automating User Manual Creation in GlueSQL","description":"Test-Driven Documentation - Automating User Manual Creation in GlueSQL","date":"2023-05-30T00:00:00.000Z","formattedDate":"May 30, 2023","tags":[{"label":"ChatGPT","permalink":"/docs/0.16.0/blog/tags/chat-gpt"},{"label":"Test-Driven-Documentation","permalink":"/docs/0.16.0/blog/tags/test-driven-documentation"},{"label":"TDD","permalink":"/docs/0.16.0/blog/tags/tdd"},{"label":"Database","permalink":"/docs/0.16.0/blog/tags/database"},{"label":"Documentation","permalink":"/docs/0.16.0/blog/tags/documentation"},{"label":"Automation","permalink":"/docs/0.16.0/blog/tags/automation"}],"readingTime":9.265,"hasTruncateMarker":false,"authors":[{"name":"Taehoon Moon","title":"Creator of GlueSQL","url":"https://github.com/panarch","image_url":"https://github.com/panarch.png","imageURL":"https://github.com/panarch.png"}],"frontMatter":{"title":"Test-Driven Documentation - Automating User Manual Creation in GlueSQL","description":"Test-Driven Documentation - Automating User Manual Creation in GlueSQL","slug":"test-driven-documentation","authors":[{"name":"Taehoon Moon","title":"Creator of GlueSQL","url":"https://github.com/panarch","image_url":"https://github.com/panarch.png","imageURL":"https://github.com/panarch.png"}],"tags":["ChatGPT","Test-Driven-Documentation","TDD","Database","Documentation","Automation"]},"prevItem":{"title":"GlueSQL - Revolutionizing Databases by Unifying Query Interfaces","permalink":"/docs/0.16.0/blog/revolutionizing-databases-by-unifying-query-interfaces"},"nextItem":{"title":"Breaking the Boundary between SQL and NoSQL Databases","permalink":"/docs/0.16.0/blog/breaking-the-boundary-between-sql-and-nosql"}},"content":"## Introduction: GlueSQL and Test-Driven Documentation\\nRecently, the GlueSQL project reached a significant milestone with the release of version 0.14. This new version brings a host of fresh features to the table, yet one of the most notable changes is in the realm of documentation. For the first time, we\'re proud to announce the launch of our official documentation website. Interested readers can explore the full range of user manuals at https://gluesql.org/docs.\\n\\nPrior to this update, the only way to navigate GlueSQL was by manually inspecting the test code within the test suite. With the recent release, however, a comprehensive user manual has been made public to facilitate a more user-friendly experience. We hope that this new addition will prove beneficial to a broad spectrum of users.\\n\\nThe task of compiling an entire database manual in one go was daunting due to the sheer volume of content required. Surprisingly, this process turned out to be smoother than initially anticipated, largely due to the invaluable aid of ChatGPT, which was instrumental in automating much of the document creation. Specifically, around 80% of the SQL Syntax section was generated using this tool.\\n\\nThis remarkable feat was only possible due to the solid foundation of test codes previously established in GlueSQL. In this article, we\'ll share how we managed to leverage ChatGPT in such a unique way. Based on our recent experience of crafting documents grounded in testing, we\'ve begun to consider the possibility of entirely automating document creation, save for the initial stages.\\n\\nAlong with sharing our journey so far, we will also reveal our plans for future test-based automation of documentation within GlueSQL.\\n\\n## Test Codes and Documentation\\nThe GlueSQL project has placed a significant emphasis on writing test codes. This might be a given for a database project; however, the thoroughness of our approach is evident from our line coverage of nearly **99%** for core codes. While we devoted considerable effort to creating these test codes, our primary focus has always been on a different aspect: ensuring that anyone can quickly grasp the content of the tests and easily add new ones.\\n\\nThe intent here is to empower newcomers to GlueSQL to understand the functionality of the software solely by examining integration tests, even in the absence of a user manual.\\n\\nThe integration tests for GlueSQL can be found in the test-suite workspace. For example, here\'s an excerpt of the test code for the INSERT statement:\\n\\n```rust\\ntest_case!(insert, async move {\\n run!(\\n \\"\\nCREATE TABLE Test (\\n id INTEGER DEFAULT 1,\\n num INTEGER NULL,\\n name TEXT NOT NULL,\\n);\\"\\n );\\n\\n test! {\\n name: \\"basic insert - single item\\",\\n sql: \\"INSERT INTO Test (id, num, name) VALUES (1, 2, \'Hi boo\');\\",\\n expected: Ok(Payload::Insert(1))\\n };\\n\\n\\n test! {\\n sql: \\"INSERT INTO Test VALUES(17, 30, \'Sullivan\');\\",\\n expected: Ok(Payload::Insert(1))\\n };\\n\\n test! {\\n sql: \\"INSERT INTO Test (num, name) VALUES (28, \'Wazowski\');\\",\\n expected: Ok(Payload::Insert(1))\\n };\\n\\n test! {\\n sql: \\"SELECT * FROM Test;\\",\\n expected: Ok(select!(\\n id | num | name;\\n I64 | I64 | Str;\\n 1 2 \\"Hi boo\\".to_owned();\\n 3 9 \\"Kitty!\\".to_owned();\\n 2 7 \\"Monsters\\".to_owned();\\n 17 30 \\"Sullivan\\".to_owned();\\n 1 28 \\"Wazowski\\".to_owned()\\n ))\\n };\\n\\n // ...\\n});\\n```\\n\\nDespite being written in Rust, these test cases are designed to be comprehensible, even to those unfamiliar with the language. Each test is a complete scenario from start to finish, and the results of each operation are readily observable.\\n\\nGiven that identifying results from SELECT operations in the form of Rust enums and structs can be challenging, we actively utilized macros such as `select!` and `select_with_null!`. We\'ve composed the test cases to demonstrate that the INSERT statement can handle a wide range of cases, including specifying all columns, omitting some, or omitting all.\\n\\n```rust\\ntest! {\\n sql: \\"INSERT INTO Test (id, num) VALUES (1, 10);\\",\\n expected: Err(InsertError::LackOfRequiredColumn(\\"name\\".to_owned()).into())\\n};\\n```\\n\\nThe tests also include scenarios for expected faulty inputs, indicating the error returns in these situations.\\n\\nBy organizing the tests in this manner, we aim to make it easy for anyone to read and write tests. Our goal was for these tests to serve as \\"documentation\\" for GlueSQL contributors. At the time we were writing these tests, we didn\'t anticipate that they could actually become documentation themselves. But we\'ve come to realize that they have extraordinary potential.\\n\\n## Leveraging ChatGPT\\nWhen we first embarked on writing the User Manual, we were overwhelmed by the sheer volume of content we had to generate. Around the same time, ChatGPT was gaining prominence, and we thought it might be worth trying out, if only to lighten our load slightly.\\n\\nTo our surprise, ChatGPT exceeded our expectations. If the test codes were well written, it was capable of automatically crafting an exceptional document based on them, capturing all essential details.\\n\\nAfter several trials and errors, we settled on the following prompt for document generation. While it\'s still a challenge to use the same prompt for all documentation, we made minor modifications to suit different situations:\\n\\n```\\nI\'m creating an SQL database documentation website, and I\'d like you to help me with one of the pages that introduces the SQL syntax for GlueSQL.\\n\\n1. Please provide the response content in the \\"markdown\\" format, so I can copy and paste it directly. Keep this constraint in mind while writing. \\n2. Regardless of the language I use, I need the content written in English. \\n3. I will provide some test case code written in the Rust language, which contains SQL examples. Please write the documentation based on these examples, but feel free to change the table names, column names, and data types as needed. Don\'t include any Rust related content or text in the response. all the response code example should be in plain SQL. \\n4. GlueSQL does not have the VARCHAR type. If you want to use that, please use TEXT instead. You don\'t need to mention this in the response. \\n5. Wrap the entire response text using
 and 
tags so I can copy all the content easily. \\n\\nNow, I\'d like you to write the following request: \\nSQL Statement - \\"INSERT\\" \\n\\nHere\'s an example test code you can refer to:\\n\\ntest_case!(insert, async move {\\n run!(...\\n```\\n\\nGenerally, we used the template above, and copied and pasted the test code from our existing test-suite. We leveraged this method to harness our many tests to assist in the creation of the user manual. In the next section, we\'ll showcase a sample of the documentation generated in this manner. It\'s quite impressive.\\n\\n## Success Case: Automated User Manual of GlueSQL\\nThanks to ChatGPT, the resulting INSERT document page can be viewed at the following link. It\'s important to note that we used ChatGPT 4 for this task. Version 3.5 wasn\'t quite up to the task, and using version 4 was the minimum requirement.\\n\\nhttps://gluesql.org/docs/dev/sql-syntax/statements/data-manipulation/insert\\n\\n![INSERT Statement](./assets/blog-test-driven-documentation-insert.jpg)\\n\\nThe results were quite impressive. ChatGPT neatly categorized the test cases, explained the syntax, outlined constraints, and provided appropriate examples. It didn\'t stop there; it also skillfully recognized error test cases and incorporated them into the documentation, as shown below.\\n\\n![INSERT Statement](./assets/blog-test-driven-documentation-insert-errorcase.jpg)\\n\\nIsn\'t it amazing?\\n\\n## Future Plans: Fully Automating Documentation Generation\\nWhile the current documentation is far from perfect and there are many aspects that can be improved, we see great potential in this approach. We believe it\'s entirely possible to automate the process of writing this kind of document, and writing in general.\\n\\nIn the past, documents like user manuals required a great deal of effort to maintain once they were written. If a document contained real code examples, verifying that the code still worked was often a tedious task. With the ability to automatically generate documentation as we have done here, these issues are no longer problematic.\\n\\nPreviously, you would have to write tests and then also document them separately. If you had to support multiple languages, that would be an additional task. With a tool like ChatGPT, you can automate all of this. All a developer has to do is write the tests. This alone can be sufficient. You can generate documents automatically based on the tests. Eventually, we can even support automatically translating these documents into multiple languages.\\n\\nThe GlueSQL project repository is currently hosted on GitHub and makes good use of various GitHub Actions. We envision a GitHub Action that automatically regenerates a document corresponding to a test when a user modifies the test and raises a Pull Request. Another GitHub Action could automatically translate updated documents into supported languages and create new Pull Requests. The possibilities are truly endless.\\n\\nNot only will this help with document generation, but it will also provide clear guidelines for writing better test code. If we can automatically generate documents based on written tests, the quality of those documents can serve as an indicator of the quality of the tests themselves. This means that a document automation tool can play the role of a good reviewer for tests. It can greatly reduce the time and effort required for painstakingly reviewing the quality of each test. Developers can also write tests without pressure, evaluate their test code by looking at the generated document, and improve it.\\n\\nFurthermore, multi-language support becomes a breeze. In my personal experience as a software engineer over the past decade, developing various products such as games, web services, and applications, I often needed to support multiple languages. Each time, there was no definite solution. The optimal approach varied depending on the situation, and there were many things to consider when entrusting translations, such as effectively communicating the context of the target service to the translator. Moreover, regularly updating content and having it retranslated into various languages was a very tedious process. While I tried to automate as much as possible by creating various tools, I was never fully satisfied. I believe ChatGPT can completely solve these issues. If there is a need to provide project-specific context, all you need to do is prepare a prompt in advance. Instead of having to rely on and wait for professional translators, we can now entrust this task to ChatGPT, and we only need a few people to review the translated content.\\n\\nWe are nearing a world where documentation is no longer a burden for developers.\\n\\n## Conclusion: The Value of Test-Driven Documentation\\nThe use of ChatGPT to generate documentation has proven a significant step forward in the GlueSQL user manual creation process. Through test-driven documentation, we\'ve managed to automate a substantial part of the manual creation process, saving time and effort, and increasing accuracy.\\n\\nMoreover, this process has unveiled a new potential for documentation: the possibility of fully automating document generation. We\'ve seen that quality tests can become quality documentation with the help of AI, leading to more efficient workflows and possibly better test code as a result.\\n\\nThe journey doesn\'t stop here. We envision leveraging this capability further to auto-translate our documents into multiple languages, making our product more accessible to a global audience.\\n\\nAs we progress, we hope that our experience can inspire other developers to explore and embrace the benefits of AI-generated, test-driven documentation. It\'s not just about saving time\u2014it\'s about improving the way we work, communicate, and share knowledge."},{"id":"breaking-the-boundary-between-sql-and-nosql","metadata":{"permalink":"/docs/0.16.0/blog/breaking-the-boundary-between-sql-and-nosql","source":"@site/blog/2023-05-29-breaking-the-boundary.md","title":"Breaking the Boundary between SQL and NoSQL Databases","description":"Breaking the Boundary between SQL and NoSQL Databases","date":"2023-05-29T00:00:00.000Z","formattedDate":"May 29, 2023","tags":[{"label":"sql","permalink":"/docs/0.16.0/blog/tags/sql"},{"label":"database","permalink":"/docs/0.16.0/blog/tags/database"},{"label":"nosql","permalink":"/docs/0.16.0/blog/tags/nosql"}],"readingTime":10.055,"hasTruncateMarker":false,"authors":[{"name":"Taehoon Moon","title":"Creator of GlueSQL","url":"https://github.com/panarch","image_url":"https://github.com/panarch.png","imageURL":"https://github.com/panarch.png"}],"frontMatter":{"title":"Breaking the Boundary between SQL and NoSQL Databases","description":"Breaking the Boundary between SQL and NoSQL Databases","slug":"breaking-the-boundary-between-sql-and-nosql","authors":[{"name":"Taehoon Moon","title":"Creator of GlueSQL","url":"https://github.com/panarch","image_url":"https://github.com/panarch.png","imageURL":"https://github.com/panarch.png"}],"tags":["sql","database","nosql"]},"prevItem":{"title":"Test-Driven Documentation - Automating User Manual Creation in GlueSQL","permalink":"/docs/0.16.0/blog/test-driven-documentation"},"nextItem":{"title":"Release v0.14","permalink":"/docs/0.16.0/blog/release-v0.14"}},"content":"## Introduction\\nThe divide between SQL and NoSQL databases has often presented challenges in database management. GlueSQL, a unique database maker library, aims to blur this boundary, providing a versatile tool for handling these two distinct types of databases.\\n\\nIn this article, we explore how GlueSQL navigates the features of SQL and NoSQL databases, offering an integrated solution that promotes flexibility and efficiency. With its ability to unify disparate database types, GlueSQL heralds a new age of adaptable database creation and management.\\n\\n## The Interface Perspective: SQL & AST Builder\\nWhen we talk about SQL databases, it\'s almost a given that they support SQL - the standard query language. Although there are slight variations between databases, the convenience of using a similar SQL language across multiple databases cannot be overstated. However, from a software engineer\'s perspective, there\'s room for improvement. In most software development scenarios, a specific programming language is used. SQL is a separate language, which can cause friction when integrating it into your software. As a result, rather than using raw SQL, many developers employ query builders or ORMs to manipulate SQL conveniently using their preferred programming language. Although it\'s not efficient to generate SQL using a query builder and then parse it again in the database, it\'s a practical and effective choice.\\n\\nOn the other hand, NoSQL databases offer different mechanisms. Some of them have their own language similar to SQL, but most provide an interface library developed specifically for each programming language. While SQL databases rely on external query builder libraries to provide an interface for each programming language, NoSQL databases mostly develop and offer these libraries themselves. If we discount the convenience of SQL language, this is one of the major factors that make NoSQL databases more comfortable to use. Since query builder libraries supporting SQL databases often cater to multiple SQL databases, they are limited in fully supporting unique features of each database. NoSQL databases, on the other hand, can freely manage their interface libraries without these restrictions.\\n\\nProviding a query interface for each programming language is not a fundamental difference between SQL and NoSQL, but we generally accept it implicitly.\\n\\nLet\'s see what happens if we break down this boundary, using GlueSQL as an example. As you can see from the SQL postfix, GlueSQL supports SQL and can be classified as an SQL database.\\n\\n```sql\\nCREATE TABLE Glue (id INTEGER, name TEXT);\\n\\nINSERT INTO Glue VALUES (1, \\"hello\\"), (2, \\"gluesql\\");\\n\\nSELECT * FROM Glue WHERE id = 1;\\n```\\n\\nHowever, GlueSQL also supports its own query builder, like a NoSQL database.\\n(Currently, only Rust is supported, but we\'re working on adding support for other languages.)\\n\\n```rust\\ntable(\\"Glue\\")\\n .create_table()\\n .add_column(\\"id INTEGER\\")\\n .add_column(\\"name TEXT\\")\\n .execute(glue)\\n\\ntable(\\"Glue\\")\\n .insert()\\n .values(vec![\\n vec![num(1), text(\\"hello\\")],\\n vec![num(2), text(\\"gluesql\\")],\\n ])\\n .execute(glue)\\n .await;\\n\\ntable(\\"Glue\\")\\n .select()\\n .filter(col(\\"id\\").eq(1))\\n .execute(glue)\\n .await;\\n```\\n\\nLet\'s reconsider the implicit distinction between SQL and NoSQL. GlueSQL indeed supports SQL, but it also officially develops and offers its own query builder. This query builder is not a secondary tool for SQL. While most SQL query builder libraries ultimately generate SQL strings, GlueSQL\'s builder directly creates an AST (Abstract Structure Tree) that is used for execution within GlueSQL. Hence, we call it the AST Builder. This means SQL and the AST Builder are two equally supported interfaces in GlueSQL.\\n\\nThis also offers an additional advantage:\\n\\n```rust\\ntable(\\"Glue\\")\\n .select()\\n // 1.\\n .filter(col(\\"id\\").eq(1))\\n // 2.\\n .filter(\\"id = 1\\")\\n .execute(glue)\\n .await;\\n```\\n\\nBecause GlueSQL already supports SQL, not only can you use the custom interface in the AST Builder, but you can also use familiar SQL syntax in part. Whether you use `col(\\"id\\").eq(1)` or `\\"id = 1\\"`, you can use it in the way you prefer. The AST Builder interface, although initially unfamiliar, allows a gradual migration similar to writing SQL for your convenience.\\n\\nThus, we\'ve dismantled one of the implicit distinctions between SQL and NoSQL. However, it\'s more of an implicit differentiation than a fundamental one. There are more significant design differences that we\'ll explore next.\\n\\n\\n## Structured & Unstructured Data\\nIn this section, we\'ll discuss how SQL and NoSQL handle data. SQL generally deals with structured data, and recently, it\'s been made to support semi-structured data as well. On the other hand, NoSQL supports schemaless, unstructured data. Then, we\'ll explain in detail how GlueSQL handles these two types of data. The last part of this section will provide a segue into the next section where we\'ll discuss the decomposition of database functions.\\n\\nWhen talking about SQL databases, one aspect is usually considered together: SQL databases have a defined schema.\\n\\n```sql\\nCREATE TABLE Foo (\\n id INTEGER,\\n name TEXT,\\n rate FLOAT NULL\\n);\\n```\\n\\nHowever, these days, SQL databases tend to support semi-structured data types, such as LIST or JSON. But, supporting completely schemaless, unstructured data is a different matter. SQL databases typically require a minimum schema.\\n\\nWhat about NoSQL databases? As NoSQL databases vary significantly, we can\'t make definitive statements. But let\'s consider a typical document database like MongoDB. Unlike SQL databases, it doesn\'t enforce a schema. Essentially, you can insert any form of data directly. Often, NoSQL databases support schemaless data, but they lack features that enforce a schema like SQL. They generally support structure via validation methods, rather than structured access.\\n\\nIs there no choice but to distinguish between structured data and unstructured, schemaless data so clearly? GlueSQL is being developed with the goal of being adaptable in various environments. Being forced to choose regarding this schema constraint was quite inconvenient. We started pondering if we couldn\'t benefit from both aspects - supporting both schema and schemaless data simultaneously, and we eventually found the answer. Let\'s look at how GlueSQL currently solves this issue through familiar SQL examples.\\n\\n```sql\\nCREATE TABLE Names (id INTEGER, name TEXT);\\nINSERT INTO Names VALUES (1, \'glue\'), (2, \'sql\');\\n```\\n\\nYou can create a regular table with a schema like this. But GlueSQL\'s choice for creating a schemaless table is as follows:\\n\\n```sql\\nCREATE TABLE Logs;\\nINSERT INTO Logs VALUES\\n (\'{ \\"id\\": 1, \\"value\\": 30 }\'),\\n (\'{ \\"id\\": 2, \\"rate\\": 3.0, \\"list\\": [1, 2, 3] }\'),\\n (\'{ \\"id\\": 3, \\"rate\\": 5.0, \\"value\\": 100 }\');\\n```\\n\\nIt creates a table without column definitions! If you do this, GlueSQL recognizes the table as schemaless and processes it internally.\\n\\n```sql\\nSELECT id, rate, list[0] FROM Logs WHERE id = 2;\\n```\\n\\nAlthough the way to create the table was a bit special, using it isn\'t much different from the regular SQL SELECT statement. Not only can you differentiate between schema and schemaless when creating tables, but you can also use them interchangeably!\\n\\n```sql\\nSELECT * FROM Names JOIN Logs ON Names.id = Logs.id;\\n/*\\n| id | list | name | rate | value |\\n|----|---------|------|------|-------|\\n| 1 | | glue | | 30 |\\n| 2 |[1, 2, 3]| sql | 3 | |\\n*/\\n```\\n\\nHere\'s an example of querying data by INNER JOINing the Names table, which has a schema, and the Logs table, which is schemaless. GlueSQL has resolved this problem by allowing the internal execution layer to handle both vector-type data, for cases where each row has a defined schema, and map-type data for schemaless cases.\\n\\nThanks to this, the variety of storage that can be supported through GlueSQL has expanded significantly. If there were previously limitations to supporting NoSQL databases that support schemaless data, that is no longer the case. The reference storage where you can directly experience this schemaless data support is JSON Storage. It offers features that allow you to deal directly with unstructured data like JSON using GlueSQL.\\n\\nIf GlueSQL starts from the perspective of an SQL database and expands, by providing the AST Builder directly, it once blurs the boundary, and by supporting unstructured data simultaneously, it knocks down the boundary once more. How do you like it?\\n\\n\\n## Decomposing Database Functionality: Breaking Down SQL and NoSQL Features\\nThe distinction between SQL and NoSQL is not just about whether they support unstructured data. Of course, there are examples like unstructured data, which is mainly supported only in NoSQL, but in many cases, SQL databases tend to support more diverse and complex queries. NoSQL often gains other advantages in exchange for reducing the range of query support provided by SQL databases.\\n\\nGlueSQL is ambitious. It has devised a rather interesting method to support all of this through SQL and the AST Builder, with the same interface. When we usually say SQL database, it implicitly assumes that a lot of features have been fully implemented. Create tables by specifying a schema, modify schemas with \\"alter table\\", support both clustered and non-clustered indexes, and support transactions. And there\'s so much more. But the functionality that is naturally supported in SQL databases may not be natural in other environments.\\n\\nLet\'s think about JSON Storage. GlueSQL\'s JSON Storage allows you to handle JSON, JSONL files using SQL and the AST Builder. This JSON Storage does not support atomic operations or transactions. Of course, it would be great if it did, but implementing and executing them would be a significant performance burden. In most cases, when you want to simply browse and handle JSONL files, the overhead caused by transactions can be an unnecessary burden. In this case, you want to handle JSON, JSONL files using SQL, but you don\'t necessarily need transactions.\\n\\nTo meet the requirements of these diverse environments, GlueSQL has separated the functionality of what we usually call an SQL database into multiple independent interfaces.\\n`Store`, `StoreMut`, `AlterTable`, `Transaction`, ..\\nThese are just a few of the various storage interfaces that GlueSQL currently supports.\\nThe way it works can be summarized like this:\\nIf you implement `Store`, you can use `SELECT`.\\nAnd if you implement both `Store` and `StoreMut`, you can support quite a number of basic SQL statements including `SELECT`.\\nYou can manage tables with `CREATE TABLE`, `DROP TABLE`, and handle data using `INSERT`, `UPDATE`, `DELETE` statements.\\nIf you only need to retrieve data, you only need to implement `Store`.\\nIf you want to support the `ALTER TABLE` statement, you can additionally implement the `AlterTable` interface.\\nThe Transaction interface works the same way.\\nThe interesting part is that, except for Store and StoreMut, all other storage interfaces can be implemented independently. GlueSQL allows you to choose and implement only the features you need.\\nAnd it\'s not just about providing interfaces. It also provides integration tests suitable for each situation to verify what you have implemented. You just need to implement the interface and import the corresponding test case for verification.\\n\\nIn addition to supporting both structured and unstructured data simultaneously, GlueSQL provides the ability to divide the functionality of a database into multiple independent features and selectively implement them. This allows GlueSQL to be ported to a wide variety of environments without any burden.\\n\\n## Conclusion\\nGlueSQL, while serving as a database that provides its own reference storage, is fundamentally a library designed to simplify the creation of databases. One of the substantial challenges GlueSQL had to overcome in order to support a diverse array of environments was to address the distinctive features that separate conventional SQL databases from NoSQL databases. GlueSQL achieved this through several innovative approaches, managing to support both categories simultaneously despite their significantly different characteristics.\\n\\nIt offers support for SQL alongside an AST Builder, and accommodates both structured and unstructured data. Additionally, it decomposes database functionalities into multiple independent features, allowing each environment to selectively implement the functionalities it requires.\\n\\nThese unique attributes enable GlueSQL to live up to its \'Glue\' prefix by facilitating effortless porting across various environments. While we have been developing it for several years, there is still much ground to cover. However, the fact that we are now able to introduce it publicly attests to our successful technological validation and completion of a demonstrable level of implementation.\\n\\nThrough GlueSQL, we hope to provide developers with a unified query interface that can be customized according to their needs, thereby enabling them to produce efficient products more effortlessly. There\'s a promising future ahead for GlueSQL, and we look forward to its contributions to the technology community."},{"id":"release-v0.14","metadata":{"permalink":"/docs/0.16.0/blog/release-v0.14","source":"@site/blog/2023-05-27-release-v0.14.md","title":"Release v0.14","description":"Release Note - v0.14","date":"2023-05-27T00:00:00.000Z","formattedDate":"May 27, 2023","tags":[{"label":"v0.14","permalink":"/docs/0.16.0/blog/tags/v-0-14"},{"label":"release-note","permalink":"/docs/0.16.0/blog/tags/release-note"}],"readingTime":10.24,"hasTruncateMarker":false,"authors":[{"name":"Taehoon Moon","title":"Creator of GlueSQL","url":"https://github.com/panarch","image_url":"https://github.com/panarch.png","imageURL":"https://github.com/panarch.png"}],"frontMatter":{"title":"Release v0.14","description":"Release Note - v0.14","slug":"release-v0.14","authors":[{"name":"Taehoon Moon","title":"Creator of GlueSQL","url":"https://github.com/panarch","image_url":"https://github.com/panarch.png","imageURL":"https://github.com/panarch.png"}],"tags":["v0.14","release-note"]},"prevItem":{"title":"Breaking the Boundary between SQL and NoSQL Databases","permalink":"/docs/0.16.0/blog/breaking-the-boundary-between-sql-and-nosql"}},"content":"We now provide an official documentation website at **https://gluesql.org/docs**\\n\\n## \ud83d\ude80 Features\\n\\n### \ud83c\udf40 Schemaless data support\\n\\nGlueSQL now supports creating tables without a schema, allowing for both structured and unstructured data to be stored in the same table.\\nTo create a schemaless table, simply run CREATE TABLE without specifying any columns. For more information on querying schemaless data, please refer to the following link: **[querying schemaless data](https://gluesql.org/docs/dev/sql-syntax/statements/querying/schemaless)**\\n\\n```sql\\nCREATE TABLE Bar;\\n```\\n\\nTo insert values,\\n```sql\\nINSERT INTO Bar VALUES\\n (\'{ \\"name\\": \\"ast\\", \\"value\\": 30 }\'),\\n (\'{ \\"name\\": \\"glue\\", \\"rate\\": 3.0, \\"list\\": [1, 2, 3] }\'),\\n```\\n\\nThen, selecting values from schemaless table is simple.\\n```sql\\nSELECT name, rate, list[0] FROM Bar WHERE name = \'glue\';\\n```\\n\\ne.g.\\n```sql\\nCREATE TABLE Names (id INTEGER, name TEXT);\\nINSERT INTO Names VALUES (1, \'glue\'), (2, \'sql\');\\n\\nCREATE TABLE Logs;\\nINSERT INTO Logs VALUES\\n (\'{ \\"id\\": 1, \\"value\\": 30 }\'),\\n (\'{ \\"id\\": 2, \\"rate\\": 3.0, \\"list\\": [1, 2, 3] }\'),\\n (\'{ \\"id\\": 3, \\"rate\\": 5.0, \\"value\\": 100 }\');\\n\\nSELECT * FROM Names JOIN Logs ON Names.id = Logs.id;\\n/*\\n| id | list | name | rate | value |\\n|----|---------|------|------|-------|\\n| 1 | | glue | | 30 |\\n| 2 |[1, 2, 3]| sql | 3 | |\\n*/\\n```\\n- Schemaless data support [@panarch](https://github.com/panarch) ([#1046](https://github.com/gluesql/gluesql/pull/1046))\\n\\n### \ud83c\udf40 IndexedDB & WebStorage supports in JavaScript package\\n\\nGlueSQL supports handling in-memory, localStorage, sessionStorage, and even IndexedDB using the same SQL syntax. All you need to know is how to specify the `ENGINE` when creating a table.\\n\\ne.g.\\n```sql\\nCREATE TABLE Mem (mid INTEGER) ENGINE = memory;\\nCREATE TABLE Loc (lid INTEGER) ENGINE = localStorage;\\nCREATE TABLE Ses (sid INTEGER) ENGINE = sessionStorage;\\nCREATE TABLE Idb (iid INTEGER) ENGINE = indexedDB;\\n\\nSELECT\\n mid, lid, sid, iid \\nFROM Mem\\nJOIN Loc\\nJOIN Ses\\nJOIN Idb;\\n```\\n\\n- Apply CompositeStorage to JS package [@panarch](https://github.com/panarch) ([#1084](https://github.com/gluesql/gluesql/pull/1084))\\n\\n### \ud83c\udf40 Data Types - `UINT32`, `UINT64`, `UINT128`, `POINT` and `FLOAT32`\\n- implement f32 data type [@pythonbrad](https://github.com/pythonbrad) ([#1145](https://github.com/gluesql/gluesql/pull/1145))\\n- Implement geometric `POINT` Type and geometric functions [@seonghun-dev](https://github.com/seonghun-dev) ([#1048](https://github.com/gluesql/gluesql/pull/1048))\\n- Add `UINT32`, `UINT64` and `UINT128` data types [@ChobobDev](https://github.com/ChobobDev) ([#1019](https://github.com/gluesql/gluesql/pull/1019))\\n- Add inet datatype [@pythonbrad](https://github.com/pythonbrad) ([#1080](https://github.com/gluesql/gluesql/pull/1080))\\n\\n### \ud83c\udf40 Functions - `APPEND`, `PREPEND`, `RAND`, `FIND_IDX`, `INITCAP` and `CALC_DISTANCE`\\n\\n- Feat : add calc\\\\_distance function [@seonghun-dev](https://github.com/seonghun-dev) ([#1153](https://github.com/gluesql/gluesql/pull/1153))\\n- Add `PREPEND` function for `LIST` data type [@seonghun-dev](https://github.com/seonghun-dev) ([#1149](https://github.com/gluesql/gluesql/pull/1149))\\n- add initcap function [@pythonbrad](https://github.com/pythonbrad) ([#1064](https://github.com/gluesql/gluesql/pull/1064))\\n- Implement `FIND_IDX` function [@zmrdltl](https://github.com/zmrdltl) ([#1100](https://github.com/gluesql/gluesql/pull/1100))\\n- Implement Rand function [@pythonbrad](https://github.com/pythonbrad) ([#1063](https://github.com/gluesql/gluesql/pull/1063))\\n- Add Append Function to LIST DataType [@seonghun-dev](https://github.com/seonghun-dev) ([#1047](https://github.com/gluesql/gluesql/pull/1047))\\n\\n### \ud83c\udf40 Store traits\\n\\n#### User-level custom function\\nBy implementing both the CustomFunction and CustomFunctionMut traits, users can create, use, and delete user-level custom functions. Although GlueSQL plans to continuously add various functions, users may still find them insufficient. In such cases, users can create their own user-level custom functions to supplement the built-in functions. Additionally, if there are repetitive business logic codes, they can be stored as custom functions.\\ne.g.\\n```sql\\nCREATE FUNCTION ADD_ONE (n INT, x INT DEFAULT 1) RETURN n + x;\\n\\nSELECT ADD_ONE(10) AS test;\\n\\nDROP FUNCTION ADD_ONE;\\n```\\n\\n- Support user level sql function [@pythonbrad](https://github.com/pythonbrad) ([#1095](https://github.com/gluesql/gluesql/pull/1095))\\n\\n#### Metadata\\nThe Metadata trait is an optional implementation for providing additional metadata support in GlueSQL. GlueSQL does not enforce any specific metadata implementation, allowing custom storage developers to decide which type of metadata, such as create time, modify time, etc., they want to provide.\\n\\n- Support Metadata trait [@devgony](https://github.com/devgony) ([#1096](https://github.com/gluesql/gluesql/pull/1096))\\n\\n### \ud83c\udf40 Storages\\n\\n#### JSON Storage\\n- Add JsonStorage support to CLI [@devgony](https://github.com/devgony) ([#1135](https://github.com/gluesql/gluesql/pull/1135))\\n- Rename `Jsonl`Storage to `Json`Storage [@devgony](https://github.com/devgony) ([#1128](https://github.com/gluesql/gluesql/pull/1128))\\n- Support `JSON` format in `JSONL storage` [@devgony](https://github.com/devgony) ([#1123](https://github.com/gluesql/gluesql/pull/1123))\\n- Support `Jsonl` Storage [@devgony](https://github.com/devgony) ([#1053](https://github.com/gluesql/gluesql/pull/1053))\\n\\n#### Composite Storage\\n- Add CompositeStorage which bundles multiple storages [@panarch](https://github.com/panarch) ([#1068](https://github.com/gluesql/gluesql/pull/1068))\\n\\n#### IndexedDB Storage\\n- Add IndexedDB storage support [@panarch](https://github.com/panarch) ([#1067](https://github.com/gluesql/gluesql/pull/1067))\\n\\n#### Web Storage\\n- Add WebStorage - support localStorage \\\\& sessionStorage for web browsers [@panarch](https://github.com/panarch) ([#1050](https://github.com/gluesql/gluesql/pull/1050))\\n\\n### \ud83c\udf40 Other new features\\n\\n- Wrap identifiers with double quote (`\\"`) at `to_sql` [@devgony](https://github.com/devgony) ([#1130](https://github.com/gluesql/gluesql/pull/1130))\\n- Support Values Query at ASTBuilder [@devgony](https://github.com/devgony) ([#1041](https://github.com/gluesql/gluesql/pull/1041))\\n- Support `Schema::from_ddl(ddl: &str) -> String` [@devgony](https://github.com/devgony) ([#1089](https://github.com/gluesql/gluesql/pull/1089))\\n- Support column alias for Table, Derived Table [@ding-young](https://github.com/ding-young) ([#1065](https://github.com/gluesql/gluesql/pull/1065))\\n- Support `TableFactor::{Derived, Dictionary, Series}` in AstBuilder [@devgony](https://github.com/devgony) ([#1007](https://github.com/gluesql/gluesql/pull/1007))\\n\\n## \ud83c\udf0a Interface Changes \\n\\n- Remove Store trait related cfg features, [@panarch](https://github.com/panarch) ([#1091](https://github.com/gluesql/gluesql/pull/1091))\\n- Refactor CreateTable.columns from `Vec` to `Option>` [@devgony](https://github.com/devgony) ([#1086](https://github.com/gluesql/gluesql/pull/1086))\\n- Remove `MutResult` [@panarch](https://github.com/panarch) ([#1073](https://github.com/gluesql/gluesql/pull/1073))\\n- Update all store mut trait methods to take \\\\&mut self [@panarch](https://github.com/panarch) ([#1072](https://github.com/gluesql/gluesql/pull/1072))\\n- Change StoreMut interface to use \\\\&mut self, not to take ownership [@panarch](https://github.com/panarch) ([#1071](https://github.com/gluesql/gluesql/pull/1071))\\n- Modify default ColumnOption from NOT NULL to NULL [@devgony](https://github.com/devgony) ([#997](https://github.com/gluesql/gluesql/pull/997))\\n\\n## \ud83c\udf1f Improvements\\n\\n- Add a case for insert with source [@devgony](https://github.com/devgony) ([#1211](https://github.com/gluesql/gluesql/pull/1211))\\n- Apply workspace inheritance to remaining Cargo.toml in storages/, [@panarch](https://github.com/panarch) ([#1181](https://github.com/gluesql/gluesql/pull/1181))\\n- Add nullable, key, default to `GLUE_TABLE_COLUMNS` [@devgony](https://github.com/devgony) ([#1177](https://github.com/gluesql/gluesql/pull/1177))\\n- Update core to bundle all errors using error module, [@panarch](https://github.com/panarch) ([#1178](https://github.com/gluesql/gluesql/pull/1178))\\n- Update global Error enum to display with error module prefix [@panarch](https://github.com/panarch) ([#1175](https://github.com/gluesql/gluesql/pull/1175))\\n- fix: typo [@ever0de](https://github.com/ever0de) ([#1161](https://github.com/gluesql/gluesql/pull/1161))\\n- Move the SCHEMA\\\\_PREFIX const into an impl in SledStorage [@garypen](https://github.com/garypen) ([#1151](https://github.com/gluesql/gluesql/pull/1151))\\n- Merge evaluate\\\\_stateless into evaluate, [@panarch](https://github.com/panarch) ([#1132](https://github.com/gluesql/gluesql/pull/1132))\\n- Remove memory-storage dep from JsonStorage/ Cargo.toml [@panarch](https://github.com/panarch) ([#1131](https://github.com/gluesql/gluesql/pull/1131))\\n- Simplify JsonlStorage codes [@panarch](https://github.com/panarch) ([#1126](https://github.com/gluesql/gluesql/pull/1126))\\n- Bump rust version to 1.68 [@ever0de](https://github.com/ever0de) ([#1125](https://github.com/gluesql/gluesql/pull/1125))\\n- Keep `Cargo.lock` [@ever0de](https://github.com/ever0de) ([#1121](https://github.com/gluesql/gluesql/pull/1121))\\n- Replace closure to variable in `data/interval` module [@ever0de](https://github.com/ever0de) ([#1118](https://github.com/gluesql/gluesql/pull/1118))\\n- Add `f64` support to `data::Key` [@panarch](https://github.com/panarch) ([#1114](https://github.com/gluesql/gluesql/pull/1114))\\n- Add Ord impl for Key, [@panarch](https://github.com/panarch) ([#1110](https://github.com/gluesql/gluesql/pull/1110))\\n- join\\\\_expr when in\\\\_subquery, exists expr in join constraint [@ding-young](https://github.com/ding-young) ([#1112](https://github.com/gluesql/gluesql/pull/1112))\\n- Split JS related GitHub action, [@panarch](https://github.com/panarch) ([#1109](https://github.com/gluesql/gluesql/pull/1109))\\n- Fix error handling for `ilike` function on `Literal` being treated as\u2026 [@ever0de](https://github.com/ever0de) ([#1107](https://github.com/gluesql/gluesql/pull/1107))\\n- Remove `Rc` in `validate.rs` [@ever0de](https://github.com/ever0de) ([#1106](https://github.com/gluesql/gluesql/pull/1106))\\n- Remove `Error::Storage` variant [@ever0de](https://github.com/ever0de) ([#1105](https://github.com/gluesql/gluesql/pull/1105))\\n- Replace `Box::pin` to `futures_enum::Stream` [@ever0de](https://github.com/ever0de) ([#1103](https://github.com/gluesql/gluesql/pull/1103))\\n- Remove stream unneeded map ok uses [@panarch](https://github.com/panarch) ([#1104](https://github.com/gluesql/gluesql/pull/1104))\\n- Replace `TryStream` to `Stream` [@ever0de](https://github.com/ever0de) ([#1102](https://github.com/gluesql/gluesql/pull/1102))\\n- Remove `Rc` from `ColumnValidation` [@ever0de](https://github.com/ever0de) ([#1101](https://github.com/gluesql/gluesql/pull/1101))\\n- Remove unneeded Rc uses in fetch\\\\_labels [@panarch](https://github.com/panarch) ([#1098](https://github.com/gluesql/gluesql/pull/1098))\\n- Simplify TryStreamExt using codes in join executor, [@panarch](https://github.com/panarch) ([#1097](https://github.com/gluesql/gluesql/pull/1097))\\n- Fix typo in plan/validate.rs [@ever0de](https://github.com/ever0de) ([#1093](https://github.com/gluesql/gluesql/pull/1093))\\n- Update IdbStorage to use Schema::{to\\\\_ddl, from\\\\_ddl} to manage schema \u2026 [@panarch](https://github.com/panarch) ([#1090](https://github.com/gluesql/gluesql/pull/1090))\\n- Update Cargo.toml files to inherit workspace level configs, [@panarch](https://github.com/panarch) ([#1088](https://github.com/gluesql/gluesql/pull/1088))\\n- Add Error enum to core::prelude [@panarch](https://github.com/panarch) ([#1087](https://github.com/gluesql/gluesql/pull/1087))\\n- Update `StringExt` implementation to use `str` [@ever0de](https://github.com/ever0de) ([#1082](https://github.com/gluesql/gluesql/pull/1082))\\n- Add enum `StrSlice` under enum `Evaluated` [@zmrdltl](https://github.com/zmrdltl) ([#999](https://github.com/gluesql/gluesql/pull/999))\\n- refactor plan::validate::Context.labels from String to str [@devgony](https://github.com/devgony) ([#1079](https://github.com/gluesql/gluesql/pull/1079))\\n- Replace `dyn object` to generic [@ever0de](https://github.com/ever0de) ([#1075](https://github.com/gluesql/gluesql/pull/1075))\\n- Implement ValidationContext(schema\\\\_map + alias) to enhance validation of ambiguous columns [@devgony](https://github.com/devgony) ([#883](https://github.com/gluesql/gluesql/pull/883))\\n- Remove `clone` in `check_table_factor` [@ever0de](https://github.com/ever0de) ([#1058](https://github.com/gluesql/gluesql/pull/1058))\\n- Bump rust-toolchain version to `1.66` [@ever0de](https://github.com/ever0de) ([#1057](https://github.com/gluesql/gluesql/pull/1057))\\n- Bump `sqlparser` version to `0.30` [@ever0de](https://github.com/ever0de) ([#1056](https://github.com/gluesql/gluesql/pull/1056))\\n- Replace `Box::pin` to `futures_enum` in aggregate module [@ever0de](https://github.com/ever0de) ([#1055](https://github.com/gluesql/gluesql/pull/1055))\\n- Update js/ Cargo.toml to use gloo-utils for serde handling [@panarch](https://github.com/panarch) ([#1049](https://github.com/gluesql/gluesql/pull/1049))\\n- Remove ast::ColumnOption and merge UNIQUE option to ColumnDef [@panarch](https://github.com/panarch) ([#1044](https://github.com/gluesql/gluesql/pull/1044))\\n- Rewrite \\\\& simplify plan/context.rs codes, [@panarch](https://github.com/panarch) ([#1045](https://github.com/gluesql/gluesql/pull/1045))\\n- Move ast::ColumnOption::Default variant to ColumnDef [@panarch](https://github.com/panarch) ([#1042](https://github.com/gluesql/gluesql/pull/1042))\\n- [AST-Builder] Remove unused prebuild nodes [@ding-young](https://github.com/ding-young) ([#1043](https://github.com/gluesql/gluesql/pull/1043))\\n- Remove data::RowError, [@panarch](https://github.com/panarch) ([#1040](https://github.com/gluesql/gluesql/pull/1040))\\n- Reorder project in ASTBuilder (project -> ordery\\\\_by -> limit,offset) [@devgony](https://github.com/devgony) ([#1039](https://github.com/gluesql/gluesql/pull/1039))\\n- Remove unused LimitOffsetNode in AST builder [@panarch](https://github.com/panarch) ([#1038](https://github.com/gluesql/gluesql/pull/1038))\\n- Rename executor/ blend.rs module to project.rs [@SaumyaBhushan](https://github.com/SaumyaBhushan) ([#1036](https://github.com/gluesql/gluesql/pull/1036))\\n- Add Debug to AST builder nodes [@panarch](https://github.com/panarch) ([#1022](https://github.com/gluesql/gluesql/pull/1022))\\n- Bump rust toolchain version to 1.65 [@ever0de](https://github.com/ever0de) ([#1035](https://github.com/gluesql/gluesql/pull/1035))\\n- Remove `Content::Shared` variant in executor/ `RowContext` [@ever0de](https://github.com/ever0de) ([#1032](https://github.com/gluesql/gluesql/pull/1032))\\n- Merge insert logics in row.rs \\\\& execute.rs into executor/insert.rs [@panarch](https://github.com/panarch) ([#1031](https://github.com/gluesql/gluesql/pull/1031))\\n- Merge FilterContext and BlendContext into RowContext [@panarch](https://github.com/panarch) ([#1029](https://github.com/gluesql/gluesql/pull/1029))\\n- Update `data::Row` to contain columns [@panarch](https://github.com/panarch) ([#1026](https://github.com/gluesql/gluesql/pull/1026))\\n- Add LIST type support in CONCAT function [@seonghun-dev](https://github.com/seonghun-dev) ([#1021](https://github.com/gluesql/gluesql/pull/1021))\\n- Remove LimitOffsetNode in AST builder [@panarch](https://github.com/panarch) ([#1023](https://github.com/gluesql/gluesql/pull/1023))\\n- Fix typo [@ever0de](https://github.com/ever0de) ([#1020](https://github.com/gluesql/gluesql/pull/1020))\\n- Add NumericNode to handle numeric value inputs in AST builder [@panarch](https://github.com/panarch) ([#1017](https://github.com/gluesql/gluesql/pull/1017))\\n- Update ValueError::InvalidJsonString error to show input text [@panarch](https://github.com/panarch) ([#1018](https://github.com/gluesql/gluesql/pull/1018))\\n- Add null() func which makes NULL value in AST builder [@panarch](https://github.com/panarch) ([#1016](https://github.com/gluesql/gluesql/pull/1016))\\n- Add --all-targets option to cargo clippy rust gh-action [@panarch](https://github.com/panarch) ([#1015](https://github.com/gluesql/gluesql/pull/1015))\\n- Move import `ColumnOption` used only by `alter-table` feature in ast-builder [@ever0de](https://github.com/ever0de) ([#1014](https://github.com/gluesql/gluesql/pull/1014))\\n- Add value/ binary\\\\_op `Parital{Ord,Cmp}` impl macro [@ever0de](https://github.com/ever0de) ([#1013](https://github.com/gluesql/gluesql/pull/1013))\\n- Change to use internal chrono errors in parsing datetime [@ever0de](https://github.com/ever0de) ([#1010](https://github.com/gluesql/gluesql/pull/1010))\\n- Resolve unreachable branch of `Value::position` [@ever0de](https://github.com/ever0de) ([#1012](https://github.com/gluesql/gluesql/pull/1012))\\n- Apply binary\\\\_op macros to existing data types [@ChobobDev](https://github.com/ChobobDev) ([#987](https://github.com/gluesql/gluesql/pull/987))\\n- chore: Use rust-cache action to cache dependencies [@jongwooo](https://github.com/jongwooo) ([#1006](https://github.com/gluesql/gluesql/pull/1006))\\n- Group the import statements [@yugeeklab](https://github.com/yugeeklab) ([#1005](https://github.com/gluesql/gluesql/pull/1005))\\n- Make Tester::new async [@ShaddyDC](https://github.com/ShaddyDC) ([#1004](https://github.com/gluesql/gluesql/pull/1004))\\n- Make MemoryStorage Store trait features optional, [@panarch](https://github.com/panarch) ([#1003](https://github.com/gluesql/gluesql/pull/1003))\\n- Replace `double quotes` to `identifier` [@devgony](https://github.com/devgony) ([#1001](https://github.com/gluesql/gluesql/pull/1001))\\n- Change chrono `from_*` methods to `from_*_opt` [@ever0de](https://github.com/ever0de) ([#1000](https://github.com/gluesql/gluesql/pull/1000))\\n- Improve duplicate column names validation [@devgony](https://github.com/devgony) ([#995](https://github.com/gluesql/gluesql/pull/995))\\n- Register `lock` when `fetch_all_schemas` face `idle` [@devgony](https://github.com/devgony) ([#996](https://github.com/gluesql/gluesql/pull/996))\\n- Merge ColumnOption::{Null, NotNull} into a single option [@devgony](https://github.com/devgony) ([#986](https://github.com/gluesql/gluesql/pull/986))\\n- Update rust.yml github action to test examples/ [@panarch](https://github.com/panarch) ([#994](https://github.com/gluesql/gluesql/pull/994))\\n\\n\\n## \ud83c\udf33 Documentation\\n\\n**We now provide an official documentation website at https://gluesql.org/docs**\\n\\n- Add documentation for CLI [@devgony](https://github.com/devgony) ([#1183](https://github.com/gluesql/gluesql/pull/1183))\\n- Add ast\\\\_builder null handling doc [@LEE026](https://github.com/LEE026) ([#1209](https://github.com/gluesql/gluesql/pull/1209))\\n- Add document of datetime current date and time for ast-builder [@heewoneha](https://github.com/heewoneha) ([#1208](https://github.com/gluesql/gluesql/pull/1208))\\n- docs: write position and indexing docs [@Bangseungjae](https://github.com/Bangseungjae) ([#1206](https://github.com/gluesql/gluesql/pull/1206))\\n- Add docs/formatting for ast\\\\_builder [@sooyeonyim-t](https://github.com/sooyeonyim-t) ([#1200](https://github.com/gluesql/gluesql/pull/1200))\\n- Update math basic arithmetic docs for ast\\\\_builder [@changi1122](https://github.com/changi1122) ([#1202](https://github.com/gluesql/gluesql/pull/1202))\\n- Add pattern-matching doc for ast\\\\_builder [@LEE026](https://github.com/LEE026) ([#1199](https://github.com/gluesql/gluesql/pull/1199))\\n- Add ast builder Trimming function docs [@Bangseungjae](https://github.com/Bangseungjae) ([#1197](https://github.com/gluesql/gluesql/pull/1197))\\n- Add doc about the function Date \\\\& Time Conversion [@heewoneha](https://github.com/heewoneha) ([#1196](https://github.com/gluesql/gluesql/pull/1196))\\n- add Docs/case conversion(upper, lower, InitCap) in ast builder [@sooyeonyim-t](https://github.com/sooyeonyim-t) ([#1195](https://github.com/gluesql/gluesql/pull/1195))\\n- Add math conversion docs for ast\\\\_builder [@changi1122](https://github.com/changi1122) ([#1192](https://github.com/gluesql/gluesql/pull/1192))\\n- Added documentation for the round, ceil, and floor functions in ast-builder [@LEE026](https://github.com/LEE026) ([#1191](https://github.com/gluesql/gluesql/pull/1191))\\n- Add documentation layout for AstBuilder [@devgony](https://github.com/devgony) ([#1184](https://github.com/gluesql/gluesql/pull/1184))\\n- Add documentation for Json Storage [@devgony](https://github.com/devgony) ([#1170](https://github.com/gluesql/gluesql/pull/1170))\\n- Add documentation for math functions [@panarch](https://github.com/panarch) ([#1173](https://github.com/gluesql/gluesql/pull/1173))\\n- Add doc for datetime, geometry, list \\\\& map and other functions, [@panarch](https://github.com/panarch) ([#1172](https://github.com/gluesql/gluesql/pull/1172))\\n- Add documentation for text functions in SQL [@panarch](https://github.com/panarch) ([#1167](https://github.com/gluesql/gluesql/pull/1167))\\n- Write docs/ Supported Storages section contents, [@panarch](https://github.com/panarch) ([#1165](https://github.com/gluesql/gluesql/pull/1165))\\n- Add SQL function list with categories to docs/ [@panarch](https://github.com/panarch) ([#1166](https://github.com/gluesql/gluesql/pull/1166))\\n- Write docs/getting-started/javascript-web.md [@panarch](https://github.com/panarch) ([#1159](https://github.com/gluesql/gluesql/pull/1159))\\n- Write docs/ Developing Custom Storages contents [@panarch](https://github.com/panarch) ([#1155](https://github.com/gluesql/gluesql/pull/1155))\\n- docs: add newly added data type into README.md [@ChobobDev](https://github.com/ChobobDev) ([#1137](https://github.com/gluesql/gluesql/pull/1137))\\n- docs(readme): add discord icon to chat badge [@LeoDog896](https://github.com/LeoDog896) ([#1122](https://github.com/gluesql/gluesql/pull/1122))\\n- docs(javascript): update examples link [@LeoDog896](https://github.com/LeoDog896) ([#1108](https://github.com/gluesql/gluesql/pull/1108))\\n\\n### Docs - setup\\n\\n- Add gh-action for docs build - runs on both push \\\\& pr [@panarch](https://github.com/panarch) ([#1215](https://github.com/gluesql/gluesql/pull/1215))\\n- Setup blog based on docusaurus, [@panarch](https://github.com/panarch) ([#1212](https://github.com/gluesql/gluesql/pull/1212))\\n- Remove mdbook which is replaced by docs/ (docusaurus based) [@panarch](https://github.com/panarch) ([#1164](https://github.com/gluesql/gluesql/pull/1164))\\n- Add docusaurus deployment github action setup [@panarch](https://github.com/panarch) ([#1163](https://github.com/gluesql/gluesql/pull/1163))\\n- Update coverage, javascript and rust gh action to ignore `docs/**` pa\u2026 [@panarch](https://github.com/panarch) ([#1168](https://github.com/gluesql/gluesql/pull/1168))\\n- Update docs/ global styles, [@panarch](https://github.com/panarch) ([#1156](https://github.com/gluesql/gluesql/pull/1156))\\n- Setup new documentation based on docusaurus [@panarch](https://github.com/panarch) ([#1136](https://github.com/gluesql/gluesql/pull/1136))\\n\\n\\n## \ud83d\udccb Tests\\n\\n- Add ifnull test suite for ast\\\\_builder [@LEE026](https://github.com/LEE026) ([#1207](https://github.com/gluesql/gluesql/pull/1207))\\n- Add datetime current date and time test case for ast builder [@heewoneha](https://github.com/heewoneha) ([#1205](https://github.com/gluesql/gluesql/pull/1205))\\n- Add Position and Indexing test code [@Bangseungjae](https://github.com/Bangseungjae) ([#1203](https://github.com/gluesql/gluesql/pull/1203))\\n- Add math basic arithmetic test case for ast\\\\_builder [@changi1122](https://github.com/changi1122) ([#1201](https://github.com/gluesql/gluesql/pull/1201))\\n- Add testcase/formatting for ast\\\\_builder [@sooyeonyim-t](https://github.com/sooyeonyim-t) ([#1198](https://github.com/gluesql/gluesql/pull/1198))\\n- Add pattern\\\\_matching test cases for ast\\\\_builder [@LEE026](https://github.com/LEE026) ([#1194](https://github.com/gluesql/gluesql/pull/1194))\\n- Add test code function / text / trimming [@Bangseungjae](https://github.com/Bangseungjae) ([#1190](https://github.com/gluesql/gluesql/pull/1190))\\n- Add Testcase/case conversion [@sooyeonyim-t](https://github.com/sooyeonyim-t) ([#1193](https://github.com/gluesql/gluesql/pull/1193))\\n- Add datetime conversion test cases for ast\\\\_builder [@heewoneha](https://github.com/heewoneha) ([#1187](https://github.com/gluesql/gluesql/pull/1187))\\n- Add math conversion test case for ast\\\\_builder [@changi1122](https://github.com/changi1122) ([#1189](https://github.com/gluesql/gluesql/pull/1189))\\n- Add rounding test cases for ast\\\\_builder [@LEE026](https://github.com/LEE026) ([#1186](https://github.com/gluesql/gluesql/pull/1186))\\n- Update delete and insert tests in test-suite/, [@panarch](https://github.com/panarch) ([#1180](https://github.com/gluesql/gluesql/pull/1180))\\n- Remove gen-\\\\_transaction\\\\_dictionary\\\\_tests! in test-suite, [@panarch](https://github.com/panarch) ([#1179](https://github.com/gluesql/gluesql/pull/1179))\\n- Refactor geometry function tests in test-suite, [@panarch](https://github.com/panarch) ([#1176](https://github.com/gluesql/gluesql/pull/1176))\\n- Refactor SQL function tests in test-suite, [@panarch](https://github.com/panarch) ([#1174](https://github.com/gluesql/gluesql/pull/1174))\\n- fix : fix missing intg test for new data type [@ChobobDev](https://github.com/ChobobDev) ([#1143](https://github.com/gluesql/gluesql/pull/1143))\\n- Add unit tests for `TryFrom<&Value> for Decimal` [@ChobobDev](https://github.com/ChobobDev) ([#1139](https://github.com/gluesql/gluesql/pull/1139))\\n- Add \\"cli\\" unittest [@pythonbrad](https://github.com/pythonbrad) ([#1094](https://github.com/gluesql/gluesql/pull/1094))\\n- Add `core/data` module unit tests [@pythonbrad](https://github.com/pythonbrad) ([#1092](https://github.com/gluesql/gluesql/pull/1092))\\n\\n## \ud83d\udc1b Bug Fixes\\n\\n- Fix docusaurus pages/index broken link [@panarch](https://github.com/panarch) ([#1214](https://github.com/gluesql/gluesql/pull/1214))\\n- Fix docs/ Discord GlueSQL channel invite link address [@panarch](https://github.com/panarch) ([#1213](https://github.com/gluesql/gluesql/pull/1213))\\n- Fix InvalidJsonString error message replacing payload to fileName [@devgony](https://github.com/devgony) ([#1185](https://github.com/gluesql/gluesql/pull/1185))\\n- Fix TryFrom `Value::Str` to `u128` not to use `parse_uuid` [@ChobobDev](https://github.com/ChobobDev) ([#1134](https://github.com/gluesql/gluesql/pull/1134))\\n- Fix column alias with identifer for `TableFactor::Derived` [@ding-young](https://github.com/ding-young) ([#1119](https://github.com/gluesql/gluesql/pull/1119))\\n- Pass data even when `deleted_by` is not present [@ever0de](https://github.com/ever0de) ([#1117](https://github.com/gluesql/gluesql/pull/1117))\\n- Fix MemoryStorage \\\\& WebStorage primary key support [@panarch](https://github.com/panarch) ([#1115](https://github.com/gluesql/gluesql/pull/1115))\\n- Fix `plan::validate` to handle `CTAS` and `ITAS` adding unit test [@devgony](https://github.com/devgony) ([#1074](https://github.com/gluesql/gluesql/pull/1074))\\n- Fix test-suite tester functions to show (found, expected) shape [@panarch](https://github.com/panarch) ([#1028](https://github.com/gluesql/gluesql/pull/1028))"}]}')}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/5a8c7729.77c8d70b.js b/docs/0.16.0/assets/js/5a8c7729.77c8d70b.js new file mode 100644 index 00000000..e3ceb992 --- /dev/null +++ b/docs/0.16.0/assets/js/5a8c7729.77c8d70b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[4667],{5680:(e,n,t)=>{t.d(n,{xA:()=>p,yg:()=>y});var a=t(6540);function l(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function r(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function i(e){for(var n=1;n=0||(l[t]=e[t]);return l}(e,n);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(l[t]=e[t])}return l}var u=a.createContext({}),o=function(e){var n=a.useContext(u),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},p=function(e){var n=o(e.components);return a.createElement(u.Provider,{value:n},e.children)},g="mdxType",m={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},c=a.forwardRef((function(e,n){var t=e.components,l=e.mdxType,r=e.originalType,u=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),g=o(t),c=l,y=g["".concat(u,".").concat(c)]||g[c]||m[c]||r;return t?a.createElement(y,i(i({ref:n},p),{},{components:t})):a.createElement(y,i({ref:n},p))}));function y(e,n){var t=arguments,l=n&&n.mdxType;if("string"==typeof e||l){var r=t.length,i=new Array(r);i[0]=c;var s={};for(var u in n)hasOwnProperty.call(n,u)&&(s[u]=n[u]);s.originalType=e,s[g]="string"==typeof e?e:l,i[1]=s;for(var o=2;o{t.r(n),t.d(n,{assets:()=>u,contentTitle:()=>i,default:()=>m,frontMatter:()=>r,metadata:()=>s,toc:()=>o});var a=t(8168),l=(t(6540),t(5680));const r={},i="ABS",s={unversionedId:"sql-syntax/functions/math/abs",id:"sql-syntax/functions/math/abs",title:"ABS",description:"The ABS function is used to calculate the absolute value of a number. It takes a single numeric argument and returns the absolute value of that number. The argument can be an integer, decimal, or float value.",source:"@site/docs/sql-syntax/functions/math/abs.md",sourceDirName:"sql-syntax/functions/math",slug:"/sql-syntax/functions/math/abs",permalink:"/docs/0.16.0/sql-syntax/functions/math/abs",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"UPPER",permalink:"/docs/0.16.0/sql-syntax/functions/text/upper"},next:{title:"ACOS",permalink:"/docs/0.16.0/sql-syntax/functions/math/acos"}},u={},o=[{value:"Syntax",id:"syntax",level:2},{value:"Examples",id:"examples",level:2},{value:"Example 1: Using ABS with integer values",id:"example-1-using-abs-with-integer-values",level:3},{value:"Example 2: Using ABS with float values",id:"example-2-using-abs-with-float-values",level:3},{value:"Example 3: Using ABS with table columns",id:"example-3-using-abs-with-table-columns",level:3},{value:"Example 4: Using ABS with NULL values",id:"example-4-using-abs-with-null-values",level:3},{value:"Errors",id:"errors",level:2},{value:"Example 5: Using ABS with non-numeric values",id:"example-5-using-abs-with-non-numeric-values",level:3},{value:"Example 6: Using ABS with multiple arguments",id:"example-6-using-abs-with-multiple-arguments",level:3}],p={toc:o},g="wrapper";function m(e){let{components:n,...t}=e;return(0,l.yg)(g,(0,a.A)({},p,t,{components:n,mdxType:"MDXLayout"}),(0,l.yg)("h1",{id:"abs"},"ABS"),(0,l.yg)("p",null,"The ",(0,l.yg)("inlineCode",{parentName:"p"},"ABS")," function is used to calculate the absolute value of a number. It takes a single numeric argument and returns the absolute value of that number. The argument can be an integer, decimal, or float value."),(0,l.yg)("h2",{id:"syntax"},"Syntax"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"ABS(value)\n")),(0,l.yg)("ul",null,(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("inlineCode",{parentName:"li"},"value"),": A numeric expression for which the absolute value is to be calculated.")),(0,l.yg)("h2",{id:"examples"},"Examples"),(0,l.yg)("p",null,"Let's consider a table named ",(0,l.yg)("inlineCode",{parentName:"p"},"SingleItem")," with the following schema:"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE SingleItem (id INTEGER, int8 INT8, dec DECIMAL);\n")),(0,l.yg)("p",null,"Insert a row into the ",(0,l.yg)("inlineCode",{parentName:"p"},"SingleItem")," table:"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO SingleItem VALUES (0, -1, -2);\n")),(0,l.yg)("h3",{id:"example-1-using-abs-with-integer-values"},"Example 1: Using ABS with integer values"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT ABS(1) AS ABS1, \n ABS(-1) AS ABS2, \n ABS(+1) AS ABS3 \nFROM SingleItem;\n")),(0,l.yg)("p",null,"Result:"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre"}," ABS1 | ABS2 | ABS3 \n------+------+------\n 1 | 1 | 1 \n")),(0,l.yg)("h3",{id:"example-2-using-abs-with-float-values"},"Example 2: Using ABS with float values"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT ABS(1.0) AS ABS1, \n ABS(-1.0) AS ABS2, \n ABS(+1.0) AS ABS3 \nFROM SingleItem;\n")),(0,l.yg)("p",null,"Result:"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre"}," ABS1 | ABS2 | ABS3 \n------+------+------\n 1.0 | 1.0 | 1.0 \n")),(0,l.yg)("h3",{id:"example-3-using-abs-with-table-columns"},"Example 3: Using ABS with table columns"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT ABS(id) AS ABS1, \n ABS(int8) AS ABS2, \n ABS(dec) AS ABS3 \nFROM SingleItem;\n")),(0,l.yg)("p",null,"Result:"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre"}," ABS1 | ABS2 | ABS3 \n------+------+------\n 0 | 1 | 2 \n")),(0,l.yg)("h3",{id:"example-4-using-abs-with-null-values"},"Example 4: Using ABS with NULL values"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT ABS(NULL) AS ABS FROM SingleItem;\n")),(0,l.yg)("p",null,"Result:"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre"}," ABS \n-------\n (null)\n")),(0,l.yg)("h2",{id:"errors"},"Errors"),(0,l.yg)("p",null,"The ",(0,l.yg)("inlineCode",{parentName:"p"},"ABS")," function requires a numeric value as its argument. Using non-numeric values or more than one argument will result in an error."),(0,l.yg)("h3",{id:"example-5-using-abs-with-non-numeric-values"},"Example 5: Using ABS with non-numeric values"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT ABS('string') AS ABS FROM SingleItem;\n")),(0,l.yg)("p",null,"Error: Function requires a numeric value."),(0,l.yg)("h3",{id:"example-6-using-abs-with-multiple-arguments"},"Example 6: Using ABS with multiple arguments"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT ABS('string', 'string2') AS ABS FROM SingleItem;\n")),(0,l.yg)("p",null,"Error: Function expects 1 argument, but 2 were provided."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/5cdfb1f2.9bdca8fe.js b/docs/0.16.0/assets/js/5cdfb1f2.9bdca8fe.js new file mode 100644 index 00000000..2397a496 --- /dev/null +++ b/docs/0.16.0/assets/js/5cdfb1f2.9bdca8fe.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[4386],{5680:(e,t,n)=>{n.d(t,{xA:()=>p,yg:()=>g});var r=n(6540);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var d=r.createContext({}),l=function(e){var t=r.useContext(d),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=l(e.components);return r.createElement(d.Provider,{value:t},e.children)},c="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,d=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),c=l(n),m=o,g=c["".concat(d,".").concat(m)]||c[m]||u[m]||a;return n?r.createElement(g,i(i({ref:t},p),{},{components:n})):r.createElement(g,i({ref:t},p))}));function g(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,i=new Array(a);i[0]=m;var s={};for(var d in t)hasOwnProperty.call(t,d)&&(s[d]=t[d]);s.originalType=e,s[c]="string"==typeof e?e:o,i[1]=s;for(var l=2;l{n.r(t),n.d(t,{assets:()=>d,contentTitle:()=>i,default:()=>u,frontMatter:()=>a,metadata:()=>s,toc:()=>l});var r=n(8168),o=(n(6540),n(5680));const a={sidebar_position:8},i="IndexMut",s={unversionedId:"storages/developing-custom-storages/store-traits/index-mut",id:"storages/developing-custom-storages/store-traits/index-mut",title:"IndexMut",description:"The IndexMut trait, when implemented along with the Index trait, allows custom storage developers to provide users with the ability to create, use, and delete non-clustered indexes. Implementing the IndexMut trait enhances the storage system's capabilities by providing support for dynamic index management.",source:"@site/docs/storages/developing-custom-storages/store-traits/index-mut.md",sourceDirName:"storages/developing-custom-storages/store-traits",slug:"/storages/developing-custom-storages/store-traits/index-mut",permalink:"/docs/0.16.0/storages/developing-custom-storages/store-traits/index-mut",draft:!1,tags:[],version:"current",sidebarPosition:8,frontMatter:{sidebar_position:8},sidebar:"autoSidebar",previous:{title:"Index",permalink:"/docs/0.16.0/storages/developing-custom-storages/store-traits/index-trait"},next:{title:"Metadata",permalink:"/docs/0.16.0/storages/developing-custom-storages/store-traits/metadata"}},d={},l=[],p={toc:l},c="wrapper";function u(e){let{components:t,...n}=e;return(0,o.yg)(c,(0,r.A)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,o.yg)("h1",{id:"indexmut"},"IndexMut"),(0,o.yg)("p",null,"The ",(0,o.yg)("inlineCode",{parentName:"p"},"IndexMut")," trait, when implemented along with the ",(0,o.yg)("inlineCode",{parentName:"p"},"Index")," trait, allows custom storage developers to provide users with the ability to create, use, and delete non-clustered indexes. Implementing the ",(0,o.yg)("inlineCode",{parentName:"p"},"IndexMut")," trait enhances the storage system's capabilities by providing support for dynamic index management."),(0,o.yg)("p",null,"Non-clustered indexes can improve query performance by reducing the amount of data that needs to be read during search operations. Users can create multiple non-clustered indexes tailored to their specific use cases, providing a more efficient and optimized experience when working with large datasets."),(0,o.yg)("p",null,"The ",(0,o.yg)("inlineCode",{parentName:"p"},"IndexMut")," trait requires the implementation of two methods:"),(0,o.yg)("ol",null,(0,o.yg)("li",{parentName:"ol"},(0,o.yg)("p",{parentName:"li"},(0,o.yg)("inlineCode",{parentName:"p"},"create_index"),": This method creates a new non-clustered index on the specified column with a given index name for the provided table. The index can be used to speed up queries involving the indexed column.")),(0,o.yg)("li",{parentName:"ol"},(0,o.yg)("p",{parentName:"li"},(0,o.yg)("inlineCode",{parentName:"p"},"drop_index"),": This method removes a non-clustered index by the specified index name from the provided table. This can be useful when the index is no longer needed or needs to be updated to reflect changes in the data."))),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-rust"},"#[async_trait(?Send)]\npub trait IndexMut {\n async fn create_index(\n &mut self,\n _table_name: &str,\n _index_name: &str,\n _column: &OrderByExpr,\n ) -> Result<()>;\n\n async fn drop_index(&mut self, _table_name: &str, _index_name: &str) -> Result<()>;\n}\n")),(0,o.yg)("p",null,"By implementing both the ",(0,o.yg)("inlineCode",{parentName:"p"},"Index")," and ",(0,o.yg)("inlineCode",{parentName:"p"},"IndexMut")," traits, custom storage developers can provide users with the ability to manage non-clustered indexes according to their specific needs, improving overall query performance and providing a more tailored experience."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/5df6e7df.487902f2.js b/docs/0.16.0/assets/js/5df6e7df.487902f2.js new file mode 100644 index 00000000..a8b79ed0 --- /dev/null +++ b/docs/0.16.0/assets/js/5df6e7df.487902f2.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[7514],{5680:(e,r,t)=>{t.d(r,{xA:()=>l,yg:()=>y});var n=t(6540);function o(e,r,t){return r in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function s(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);r&&(n=n.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),t.push.apply(t,n)}return t}function a(e){for(var r=1;r=0||(o[t]=e[t]);return o}(e,r);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var c=n.createContext({}),p=function(e){var r=n.useContext(c),t=r;return e&&(t="function"==typeof e?e(r):a(a({},r),e)),t},l=function(e){var r=p(e.components);return n.createElement(c.Provider,{value:r},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var r=e.children;return n.createElement(n.Fragment,{},r)}},f=n.forwardRef((function(e,r){var t=e.components,o=e.mdxType,s=e.originalType,c=e.parentName,l=i(e,["components","mdxType","originalType","parentName"]),d=p(t),f=o,y=d["".concat(c,".").concat(f)]||d[f]||u[f]||s;return t?n.createElement(y,a(a({ref:r},l),{},{components:t})):n.createElement(y,a({ref:r},l))}));function y(e,r){var t=arguments,o=r&&r.mdxType;if("string"==typeof e||o){var s=t.length,a=new Array(s);a[0]=f;var i={};for(var c in r)hasOwnProperty.call(r,c)&&(i[c]=r[c]);i.originalType=e,i[d]="string"==typeof e?e:o,a[1]=i;for(var p=2;p{t.r(r),t.d(r,{assets:()=>c,contentTitle:()=>a,default:()=>u,frontMatter:()=>s,metadata:()=>i,toc:()=>p});var n=t(8168),o=(t(6540),t(5680));const s={},a="Nested",i={unversionedId:"ast-builder/expressions/nested",id:"ast-builder/expressions/nested",title:"Nested",description:"Todo",source:"@site/docs/ast-builder/expressions/nested.md",sourceDirName:"ast-builder/expressions",slug:"/ast-builder/expressions/nested",permalink:"/docs/0.16.0/ast-builder/expressions/nested",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"Conditional",permalink:"/docs/0.16.0/ast-builder/expressions/conditional"},next:{title:"Operator Based",permalink:"/docs/0.16.0/ast-builder/expressions/operator-based"}},c={},p=[{value:"Todo",id:"todo",level:2}],l={toc:p},d="wrapper";function u(e){let{components:r,...t}=e;return(0,o.yg)(d,(0,n.A)({},l,t,{components:r,mdxType:"MDXLayout"}),(0,o.yg)("h1",{id:"nested"},"Nested"),(0,o.yg)("h2",{id:"todo"},"Todo"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre"},"- NESTED: Represents a nested expression, allowing the use of complex and grouped expressions.\n")))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/5eabd930.fbc0a29f.js b/docs/0.16.0/assets/js/5eabd930.fbc0a29f.js new file mode 100644 index 00000000..4d6c2e87 --- /dev/null +++ b/docs/0.16.0/assets/js/5eabd930.fbc0a29f.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[9612],{5680:(e,t,n)=>{n.d(t,{xA:()=>c,yg:()=>y});var r=n(6540);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function l(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),u=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},c=function(e){var t=u(e.components);return r.createElement(s.Provider,{value:t},e.children)},p="mdxType",g={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,s=e.parentName,c=o(e,["components","mdxType","originalType","parentName"]),p=u(n),m=a,y=p["".concat(s,".").concat(m)]||p[m]||g[m]||i;return n?r.createElement(y,l(l({ref:t},c),{},{components:n})):r.createElement(y,l({ref:t},c))}));function y(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,l=new Array(i);l[0]=m;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[p]="string"==typeof e?e:a,l[1]=o;for(var u=2;u{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>g,frontMatter:()=>i,metadata:()=>o,toc:()=>u});var r=n(8168),a=(n(6540),n(5680));const i={},l="RIGHT",o={unversionedId:"sql-syntax/functions/text/right",id:"sql-syntax/functions/text/right",title:"RIGHT",description:"The RIGHT function in SQL returns the specified number of characters from the end (right side) of a given string.",source:"@site/docs/sql-syntax/functions/text/right.md",sourceDirName:"sql-syntax/functions/text",slug:"/sql-syntax/functions/text/right",permalink:"/docs/0.16.0/sql-syntax/functions/text/right",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"REVERSE",permalink:"/docs/0.16.0/sql-syntax/functions/text/reverse"},next:{title:"RPAD",permalink:"/docs/0.16.0/sql-syntax/functions/text/rpad"}},s={},u=[{value:"Syntax",id:"syntax",level:2},{value:"Parameters",id:"parameters",level:2},{value:"Return Value",id:"return-value",level:2},{value:"Errors",id:"errors",level:2},{value:"Examples",id:"examples",level:2}],c={toc:u},p="wrapper";function g(e){let{components:t,...n}=e;return(0,a.yg)(p,(0,r.A)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"right"},"RIGHT"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"RIGHT")," function in SQL returns the specified number of characters from the end (right side) of a given string."),(0,a.yg)("h2",{id:"syntax"},"Syntax"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"RIGHT(string, number)\n")),(0,a.yg)("h2",{id:"parameters"},"Parameters"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"string"),": The original string from which to extract characters."),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"number"),": The number of characters to extract from the end of the string. This must be an integer.")),(0,a.yg)("h2",{id:"return-value"},"Return Value"),(0,a.yg)("p",null,"The function returns a string, which consists of the specified number of characters from the end of the original string. If the original string is shorter than the specified number, the function returns the whole string."),(0,a.yg)("h2",{id:"errors"},"Errors"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},"If the ",(0,a.yg)("inlineCode",{parentName:"li"},"number")," argument is not an integer, a ",(0,a.yg)("inlineCode",{parentName:"li"},"FunctionRequiresIntegerValue")," error will be returned."),(0,a.yg)("li",{parentName:"ul"},"If the ",(0,a.yg)("inlineCode",{parentName:"li"},"string")," argument is not a string, a ",(0,a.yg)("inlineCode",{parentName:"li"},"FunctionRequiresStringValue")," error will be returned."),(0,a.yg)("li",{parentName:"ul"},"If the ",(0,a.yg)("inlineCode",{parentName:"li"},"number")," argument is negative, a ",(0,a.yg)("inlineCode",{parentName:"li"},"FunctionRequiresUSizeValue")," error will be returned.")),(0,a.yg)("h2",{id:"examples"},"Examples"),(0,a.yg)("p",null,"Consider a table ",(0,a.yg)("inlineCode",{parentName:"p"},"Item")," created and filled with the following data:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE Item (\n name TEXT\n);\nINSERT INTO Item VALUES ('Blop mc blee'), ('B'), ('Steven the &long named$ folken!');\n")),(0,a.yg)("p",null,"You can use the ",(0,a.yg)("inlineCode",{parentName:"p"},"RIGHT")," function to extract the last three characters of each ",(0,a.yg)("inlineCode",{parentName:"p"},"name"),":"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT RIGHT(name, 3) AS test FROM Item;\n")),(0,a.yg)("p",null,"This will return:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre"},"lee\nB\nen!\n")),(0,a.yg)("p",null,"Note that when the string length is less than the specified number (as with 'B'), the function will return the whole string."))}g.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/67d1434e.85b319c4.js b/docs/0.16.0/assets/js/67d1434e.85b319c4.js new file mode 100644 index 00000000..4313ccd8 --- /dev/null +++ b/docs/0.16.0/assets/js/67d1434e.85b319c4.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[4845],{5680:(e,t,o)=>{o.d(t,{xA:()=>c,yg:()=>f});var r=o(6540);function a(e,t,o){return t in e?Object.defineProperty(e,t,{value:o,enumerable:!0,configurable:!0,writable:!0}):e[t]=o,e}function n(e,t){var o=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),o.push.apply(o,r)}return o}function s(e){for(var t=1;t=0||(a[o]=e[o]);return a}(e,t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,o)&&(a[o]=e[o])}return a}var l=r.createContext({}),u=function(e){var t=r.useContext(l),o=t;return e&&(o="function"==typeof e?e(t):s(s({},t),e)),o},c=function(e){var t=u(e.components);return r.createElement(l.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},g=r.forwardRef((function(e,t){var o=e.components,a=e.mdxType,n=e.originalType,l=e.parentName,c=i(e,["components","mdxType","originalType","parentName"]),p=u(o),g=a,f=p["".concat(l,".").concat(g)]||p[g]||d[g]||n;return o?r.createElement(f,s(s({ref:t},c),{},{components:o})):r.createElement(f,s({ref:t},c))}));function f(e,t){var o=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var n=o.length,s=new Array(n);s[0]=g;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i[p]="string"==typeof e?e:a,s[1]=i;for(var u=2;u{o.r(t),o.d(t,{assets:()=>l,contentTitle:()=>s,default:()=>d,frontMatter:()=>n,metadata:()=>i,toc:()=>u});var r=o(8168),a=(o(6540),o(5680));const n={},s="Composite Storage",i={unversionedId:"storages/supported-storages/composite-storage",id:"storages/supported-storages/composite-storage",title:"Composite Storage",description:"Introduction",source:"@site/docs/storages/supported-storages/composite-storage.md",sourceDirName:"storages/supported-storages",slug:"/storages/supported-storages/composite-storage",permalink:"/docs/0.16.0/storages/supported-storages/composite-storage",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"Introduction",permalink:"/docs/0.16.0/storages/intro"},next:{title:"CSV Storage",permalink:"/docs/0.16.0/storages/supported-storages/csv-storage"}},l={},u=[{value:"Introduction",id:"introduction",level:2},{value:"Unified Interface across Different Storages",id:"unified-interface-across-different-storages",level:2},{value:"Potential and Future Plans",id:"potential-and-future-plans",level:2},{value:"Limitations and Considerations",id:"limitations-and-considerations",level:2},{value:"Summary",id:"summary",level:2}],c={toc:u},p="wrapper";function d(e){let{components:t,...o}=e;return(0,a.yg)(p,(0,r.A)({},c,o,{components:t,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"composite-storage"},"Composite Storage"),(0,a.yg)("h2",{id:"introduction"},"Introduction"),(0,a.yg)("p",null,"CompositeStorage is a special type of Storage. It does not possess any real storage implementation itself. Instead, it offers a powerful capability - the ability to bundle together multiple existing storages. For instance, with CompositeStorage, you can bundle JsonStorage and SledStorage together for simultaneous use. This means you can perform JOIN operations across two distinct storages. You can even read and analyze JSON log files, and directly insert the data into SledStorage."),(0,a.yg)("h2",{id:"unified-interface-across-different-storages"},"Unified Interface across Different Storages"),(0,a.yg)("p",null,"In fact, the Javascript (Web) GlueSQL interface already utilizes CompositeStorage. Take a look at this:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE Mem (mid INTEGER) ENGINE = memory;\nCREATE TABLE Loc (lid INTEGER) ENGINE = localStorage;\nCREATE TABLE Ses (sid INTEGER) ENGINE = sessionStorage;\nCREATE TABLE Idb (iid INTEGER) ENGINE = indexedDB;\n\nSELECT\n mid, lid, sid, iid \nFROM Mem\nJOIN Loc\nJOIN Ses\nJOIN Idb;\n")),(0,a.yg)("p",null,"You can create tables using four different storages and perform operations like JOIN using SQL! All you have to do is specify the ENGINE during ",(0,a.yg)("inlineCode",{parentName:"p"},"CREATE TABLE"),". That's all it takes."),(0,a.yg)("h2",{id:"potential-and-future-plans"},"Potential and Future Plans"),(0,a.yg)("p",null,"CompositeStorage can be immensely useful in various applications. At present, GlueSQL might not offer a plethora of reference storages. However, plans are in place to support a diverse range of storages in the future. These include log files like CSV and Parquet, and even NoSQL databases like Redis and MongoDB. They're not exceptions; they can fully provide an SQL interface via GlueSQL."),(0,a.yg)("p",null,"In addition, just as you would use an ORM to handle multiple different SQL databases with the same interface, plans are in place to use existing SQL databases in a similar way as storages in GlueSQL. Once all these plans come to fruition, you will be able to implement your data pipelines very simply."),(0,a.yg)("p",null,"Moving data from Redis to MongoDB, or from MySQL to Redis will be a breeze - just by specifying the ENGINE using the same GlueSQL SQL or AST Builder."),(0,a.yg)("h2",{id:"limitations-and-considerations"},"Limitations and Considerations"),(0,a.yg)("p",null,"CompositeStorage might sound like a cure-all solution, but it does have its limitations. As it combines different data storages, certain boundaries exist. Transactions, for instance, are a major one. Each storage may have different transaction support and methods. Therefore, it is not advisable to use CompositeStorage for operations that require transactions. It's more suitable for moving or analyzing data across different storages."),(0,a.yg)("h2",{id:"summary"},"Summary"),(0,a.yg)("p",null,"In conclusion, CompositeStorage is an exciting and powerful feature of GlueSQL, enabling users to combine and use different storage types seamlessly. However, users should also be aware of its limitations, such as transaction handling. Despite these constraints, the potential and flexibility offered by CompositeStorage make it a compelling choice for a variety of data manipulation tasks, especially when working with diverse storage types."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/6870612e.6f228bb6.js b/docs/0.16.0/assets/js/6870612e.6f228bb6.js new file mode 100644 index 00000000..fef215f6 --- /dev/null +++ b/docs/0.16.0/assets/js/6870612e.6f228bb6.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[4192],{5680:(e,n,t)=>{t.d(n,{xA:()=>c,yg:()=>m});var r=t(6540);function a(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function l(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function o(e){for(var n=1;n=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var s=r.createContext({}),u=function(e){var n=r.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):o(o({},n),e)),t},c=function(e){var n=u(e.components);return r.createElement(s.Provider,{value:n},e.children)},p="mdxType",g={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},y=r.forwardRef((function(e,n){var t=e.components,a=e.mdxType,l=e.originalType,s=e.parentName,c=i(e,["components","mdxType","originalType","parentName"]),p=u(t),y=a,m=p["".concat(s,".").concat(y)]||p[y]||g[y]||l;return t?r.createElement(m,o(o({ref:n},c),{},{components:t})):r.createElement(m,o({ref:n},c))}));function m(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var l=t.length,o=new Array(l);o[0]=y;var i={};for(var s in n)hasOwnProperty.call(n,s)&&(i[s]=n[s]);i.originalType=e,i[p]="string"==typeof e?e:a,o[1]=i;for(var u=2;u{t.r(n),t.d(n,{assets:()=>s,contentTitle:()=>o,default:()=>g,frontMatter:()=>l,metadata:()=>i,toc:()=>u});var r=t(8168),a=(t(6540),t(5680));const l={},o="SIGN",i={unversionedId:"sql-syntax/functions/math/sign",id:"sql-syntax/functions/math/sign",title:"SIGN",description:"The SIGN function is used to determine the sign of a number. It takes one argument, which must be of the FLOAT type. The result will be of the INTEGER type and can be -1, 0, or 1.",source:"@site/docs/sql-syntax/functions/math/sign.md",sourceDirName:"sql-syntax/functions/math",slug:"/sql-syntax/functions/math/sign",permalink:"/docs/0.16.0/sql-syntax/functions/math/sign",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"ROUND",permalink:"/docs/0.16.0/sql-syntax/functions/math/round"},next:{title:"SIN",permalink:"/docs/0.16.0/sql-syntax/functions/math/sin"}},s={},u=[{value:"Syntax",id:"syntax",level:2},{value:"Examples",id:"examples",level:2},{value:"Error Cases",id:"error-cases",level:2}],c={toc:u},p="wrapper";function g(e){let{components:n,...t}=e;return(0,a.yg)(p,(0,r.A)({},c,t,{components:n,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"sign"},"SIGN"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"SIGN")," function is used to determine the sign of a number. It takes one argument, which must be of the FLOAT type. The result will be of the INTEGER type and can be -1, 0, or 1."),(0,a.yg)("h2",{id:"syntax"},"Syntax"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SIGN(number)\n")),(0,a.yg)("h2",{id:"examples"},"Examples"),(0,a.yg)("ol",null,(0,a.yg)("li",{parentName:"ol"},"Using the ",(0,a.yg)("inlineCode",{parentName:"li"},"SIGN")," function with integers:")),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT SIGN(2) AS SIGN1, \n SIGN(-2) AS SIGN2, \n SIGN(+2) AS SIGN3;\n-- Result: 1, -1, 1\n")),(0,a.yg)("ol",{start:2},(0,a.yg)("li",{parentName:"ol"},"Using the ",(0,a.yg)("inlineCode",{parentName:"li"},"SIGN")," function with floats:")),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT SIGN(2.0) AS SIGN1, \n SIGN(-2.0) AS SIGN2, \n SIGN(+2.0) AS SIGN3;\n-- Result: 1, -1, 1\n")),(0,a.yg)("ol",{start:3},(0,a.yg)("li",{parentName:"ol"},"Using the ",(0,a.yg)("inlineCode",{parentName:"li"},"SIGN")," function with zero:")),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT SIGN(0.0) AS SIGN1, \n SIGN(-0.0) AS SIGN2, \n SIGN(+0.0) AS SIGN3;\n-- Result: 0, 0, 0\n")),(0,a.yg)("ol",{start:4},(0,a.yg)("li",{parentName:"ol"},"Using the ",(0,a.yg)("inlineCode",{parentName:"li"},"SIGN")," function with NULL:")),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT SIGN(NULL) AS sign;\n-- Result: NULL\n")),(0,a.yg)("h2",{id:"error-cases"},"Error Cases"),(0,a.yg)("ol",null,(0,a.yg)("li",{parentName:"ol"},"The ",(0,a.yg)("inlineCode",{parentName:"li"},"SIGN")," function requires the argument to be of FLOAT type:")),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},'SELECT SIGN(\'string\') AS SIGN;\n-- Error: FunctionRequiresFloatValue("SIGN")\n\nSELECT SIGN(TRUE) AS sign;\n-- Error: FunctionRequiresFloatValue("SIGN")\n\nSELECT SIGN(FALSE) AS sign;\n-- Error: FunctionRequiresFloatValue("SIGN")\n')),(0,a.yg)("ol",{start:2},(0,a.yg)("li",{parentName:"ol"},"The ",(0,a.yg)("inlineCode",{parentName:"li"},"SIGN")," function takes exactly one argument:")),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT SIGN('string', 'string2') AS SIGN;\n-- Error: FunctionArgsLengthNotMatching(\"SIGN\", 1, 2)\n")))}g.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/6875c492.c67f2e73.js b/docs/0.16.0/assets/js/6875c492.c67f2e73.js new file mode 100644 index 00000000..e57f9ae2 --- /dev/null +++ b/docs/0.16.0/assets/js/6875c492.c67f2e73.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[4813],{7713:(e,t,a)=>{a.d(t,{A:()=>s});var n=a(6540),l=a(1312),r=a(9022);function s(e){const{metadata:t}=e,{previousPage:a,nextPage:s}=t;return n.createElement("nav",{className:"pagination-nav","aria-label":(0,l.T)({id:"theme.blog.paginator.navAriaLabel",message:"Blog list page navigation",description:"The ARIA label for the blog pagination"})},a&&n.createElement(r.A,{permalink:a,title:n.createElement(l.A,{id:"theme.blog.paginator.newerEntries",description:"The label used to navigate to the newer blog posts page (previous page)"},"Newer Entries")}),s&&n.createElement(r.A,{permalink:s,title:n.createElement(l.A,{id:"theme.blog.paginator.olderEntries",description:"The label used to navigate to the older blog posts page (next page)"},"Older Entries"),isNext:!0}))}},3892:(e,t,a)=>{a.d(t,{A:()=>s});var n=a(6540),l=a(7131),r=a(8258);function s(e){let{items:t,component:a=r.A}=e;return n.createElement(n.Fragment,null,t.map((e=>{let{content:t}=e;return n.createElement(l.i,{key:t.metadata.permalink,content:t},n.createElement(a,null,n.createElement(t,null)))})))}},3069:(e,t,a)=>{a.r(t),a.d(t,{default:()=>E});var n=a(6540),l=a(53),r=a(1312),s=a(8227),o=a(1003),i=a(7559),g=a(5489),c=a(6669),m=a(7713),p=a(1463),u=a(3892);function d(e){const t=function(){const{selectMessage:e}=(0,s.W)();return t=>e(t,(0,r.T)({id:"theme.blog.post.plurals",description:'Pluralized label for "{count} posts". Use as much plural forms (separated by "|") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)',message:"One post|{count} posts"},{count:t}))}();return(0,r.T)({id:"theme.blog.tagTitle",description:"The title of the page for a blog tag",message:'{nPosts} tagged with "{tagName}"'},{nPosts:t(e.count),tagName:e.label})}function h(e){let{tag:t}=e;const a=d(t);return n.createElement(n.Fragment,null,n.createElement(o.be,{title:a}),n.createElement(p.A,{tag:"blog_tags_posts"}))}function b(e){let{tag:t,items:a,sidebar:l,listMetadata:s}=e;const o=d(t);return n.createElement(c.A,{sidebar:l},n.createElement("header",{className:"margin-bottom--xl"},n.createElement("h1",null,o),n.createElement(g.A,{href:t.allTagsPath},n.createElement(r.A,{id:"theme.tags.tagsPageLink",description:"The label of the link targeting the tag list page"},"View All Tags"))),n.createElement(u.A,{items:a}),n.createElement(m.A,{metadata:s}))}function E(e){return n.createElement(o.e3,{className:(0,l.A)(i.G.wrapper.blogPages,i.G.page.blogTagPostListPage)},n.createElement(h,e),n.createElement(b,e))}}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/68c17ba1.56cc7f22.js b/docs/0.16.0/assets/js/68c17ba1.56cc7f22.js new file mode 100644 index 00000000..ba8ece4c --- /dev/null +++ b/docs/0.16.0/assets/js/68c17ba1.56cc7f22.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[1296],{5680:(e,n,t)=>{t.d(n,{xA:()=>c,yg:()=>y});var a=t(6540);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function l(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function i(e){for(var n=1;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var u=a.createContext({}),o=function(e){var n=a.useContext(u),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},c=function(e){var n=o(e.components);return a.createElement(u.Provider,{value:n},e.children)},p="mdxType",m={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},g=a.forwardRef((function(e,n){var t=e.components,r=e.mdxType,l=e.originalType,u=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),p=o(t),g=r,y=p["".concat(u,".").concat(g)]||p[g]||m[g]||l;return t?a.createElement(y,i(i({ref:n},c),{},{components:t})):a.createElement(y,i({ref:n},c))}));function y(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var l=t.length,i=new Array(l);i[0]=g;var s={};for(var u in n)hasOwnProperty.call(n,u)&&(s[u]=n[u]);s.originalType=e,s[p]="string"==typeof e?e:r,i[1]=s;for(var o=2;o{t.r(n),t.d(n,{assets:()=>u,contentTitle:()=>i,default:()=>m,frontMatter:()=>l,metadata:()=>s,toc:()=>o});var a=t(8168),r=(t(6540),t(5680));const l={},i="ASIN",s={unversionedId:"sql-syntax/functions/math/asin",id:"sql-syntax/functions/math/asin",title:"ASIN",description:"The ASIN function is used to calculate the arcsine (inverse sine) of a number. It takes a single numeric argument, which should be a float value in the range of -1 to 1, and returns the arcsine of that number in radians.",source:"@site/docs/sql-syntax/functions/math/asin.md",sourceDirName:"sql-syntax/functions/math",slug:"/sql-syntax/functions/math/asin",permalink:"/docs/0.16.0/sql-syntax/functions/math/asin",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"ACOS",permalink:"/docs/0.16.0/sql-syntax/functions/math/acos"},next:{title:"ATAN",permalink:"/docs/0.16.0/sql-syntax/functions/math/atan"}},u={},o=[{value:"Syntax",id:"syntax",level:2},{value:"Examples",id:"examples",level:2},{value:"Example 1: Using ASIN with float values",id:"example-1-using-asin-with-float-values",level:3},{value:"Example 2: Using ASIN with NULL values",id:"example-2-using-asin-with-null-values",level:3},{value:"Errors",id:"errors",level:2},{value:"Example 3: Using ASIN with non-numeric values",id:"example-3-using-asin-with-non-numeric-values",level:3},{value:"Example 4: Using ASIN with multiple arguments",id:"example-4-using-asin-with-multiple-arguments",level:3}],c={toc:o},p="wrapper";function m(e){let{components:n,...t}=e;return(0,r.yg)(p,(0,a.A)({},c,t,{components:n,mdxType:"MDXLayout"}),(0,r.yg)("h1",{id:"asin"},"ASIN"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"ASIN")," function is used to calculate the arcsine (inverse sine) of a number. It takes a single numeric argument, which should be a float value in the range of -1 to 1, and returns the arcsine of that number in radians."),(0,r.yg)("h2",{id:"syntax"},"Syntax"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"ASIN(value)\n")),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"value"),": A numeric expression for which the arcsine is to be calculated. The value should be in the range of -1 to 1.")),(0,r.yg)("h2",{id:"examples"},"Examples"),(0,r.yg)("p",null,"Let's consider a table named ",(0,r.yg)("inlineCode",{parentName:"p"},"SingleItem")," with the following schema:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE SingleItem (id INTEGER);\n")),(0,r.yg)("p",null,"Insert a row into the ",(0,r.yg)("inlineCode",{parentName:"p"},"SingleItem")," table:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO SingleItem VALUES (0);\n")),(0,r.yg)("h3",{id:"example-1-using-asin-with-float-values"},"Example 1: Using ASIN with float values"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT ASIN(0.5) AS asin1, ASIN(1) AS asin2 FROM SingleItem;\n")),(0,r.yg)("p",null,"Result:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre"}," asin1 | asin2\n----------------+---------------\n 0.5235987755983 | 1.5707963267949\n")),(0,r.yg)("h3",{id:"example-2-using-asin-with-null-values"},"Example 2: Using ASIN with NULL values"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT ASIN(NULL) AS asin FROM SingleItem;\n")),(0,r.yg)("p",null,"Result:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre"}," asin\n-------\n (null)\n")),(0,r.yg)("h2",{id:"errors"},"Errors"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"ASIN")," function requires a numeric value in the range of -1 to 1 as its argument. Using non-numeric values or more than one argument will result in an error."),(0,r.yg)("h3",{id:"example-3-using-asin-with-non-numeric-values"},"Example 3: Using ASIN with non-numeric values"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT ASIN('string') AS asin FROM SingleItem;\n")),(0,r.yg)("p",null,"Error: Function requires a numeric value."),(0,r.yg)("h3",{id:"example-4-using-asin-with-multiple-arguments"},"Example 4: Using ASIN with multiple arguments"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT ASIN(1.0, 2.0) AS sin FROM SingleItem;\n")),(0,r.yg)("p",null,"Error: Function expects 1 argument, but 2 were provided."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/6a35a4d8.35bcee7f.js b/docs/0.16.0/assets/js/6a35a4d8.35bcee7f.js new file mode 100644 index 00000000..3014f8a9 --- /dev/null +++ b/docs/0.16.0/assets/js/6a35a4d8.35bcee7f.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[8439],{5680:(e,t,r)=>{r.d(t,{xA:()=>c,yg:()=>y});var a=r(6540);function n(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,a)}return r}function s(e){for(var t=1;t=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var l=a.createContext({}),p=function(e){var t=a.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},c=function(e){var t=p(e.components);return a.createElement(l.Provider,{value:t},e.children)},u="mdxType",g={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,l=e.parentName,c=i(e,["components","mdxType","originalType","parentName"]),u=p(r),d=n,y=u["".concat(l,".").concat(d)]||u[d]||g[d]||o;return r?a.createElement(y,s(s({ref:t},c),{},{components:r})):a.createElement(y,s({ref:t},c))}));function y(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,s=new Array(o);s[0]=d;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i[u]="string"==typeof e?e:n,s[1]=i;for(var p=2;p{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>s,default:()=>g,frontMatter:()=>o,metadata:()=>i,toc:()=>p});var a=r(8168),n=(r(6540),r(5680));const o={},s="CSV Storage",i={unversionedId:"storages/supported-storages/csv-storage",id:"storages/supported-storages/csv-storage",title:"CSV Storage",description:"Introducing CSVStorage: a utility to process *.csv files, enabling SQL-like query operations such as SELECT, INSERT, and UPDATE.",source:"@site/docs/storages/supported-storages/csv-storage.md",sourceDirName:"storages/supported-storages",slug:"/storages/supported-storages/csv-storage",permalink:"/docs/0.16.0/storages/supported-storages/csv-storage",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"Composite Storage",permalink:"/docs/0.16.0/storages/supported-storages/composite-storage"},next:{title:"IndexedDB Storage",permalink:"/docs/0.16.0/storages/supported-storages/idb-storage"}},l={},p=[{value:"Key Features:",id:"key-features",level:2}],c={toc:p},u="wrapper";function g(e){let{components:t,...r}=e;return(0,n.yg)(u,(0,a.A)({},c,r,{components:t,mdxType:"MDXLayout"}),(0,n.yg)("h1",{id:"csv-storage"},"CSV Storage"),(0,n.yg)("p",null,"Introducing ",(0,n.yg)("inlineCode",{parentName:"p"},"CSVStorage"),": a utility to process *.csv files, enabling SQL-like query operations such as SELECT, INSERT, and UPDATE."),(0,n.yg)("h2",{id:"key-features"},"Key Features:"),(0,n.yg)("ol",null,(0,n.yg)("li",{parentName:"ol"},(0,n.yg)("p",{parentName:"li"},(0,n.yg)("strong",{parentName:"p"},"SQL Queries on CSV"),": Directly parse and operate on *.csv files using familiar SQL query operations.")),(0,n.yg)("li",{parentName:"ol"},(0,n.yg)("p",{parentName:"li"},(0,n.yg)("strong",{parentName:"p"},"Optional Schema Support"),": An associated schema can be provided for each CSV file. For instance, for a data file named ",(0,n.yg)("inlineCode",{parentName:"p"},"Book.csv"),", its corresponding schema file should be named ",(0,n.yg)("inlineCode",{parentName:"p"},"Book.sql"),"."),(0,n.yg)("ul",{parentName:"li"},(0,n.yg)("li",{parentName:"ul"},"If an associated schema file is found, it will be read and applied."),(0,n.yg)("li",{parentName:"ul"},"In the absence of a schema file, the first row of the data file will be treated as column headers and all column types will default to TEXT."))),(0,n.yg)("li",{parentName:"ol"},(0,n.yg)("p",{parentName:"li"},(0,n.yg)("strong",{parentName:"p"},"Type Info File for Schemaless Data"),": An auxiliary types file (",(0,n.yg)("inlineCode",{parentName:"p"},"*.types.csv"),") can be used to support data type recognition for schemaless data."),(0,n.yg)("ul",{parentName:"li"},(0,n.yg)("li",{parentName:"ul"},"For a CSV data file named ",(0,n.yg)("inlineCode",{parentName:"li"},"Book.csv"),", its corresponding types file will be ",(0,n.yg)("inlineCode",{parentName:"li"},"Book.types.csv"),"."),(0,n.yg)("li",{parentName:"ul"},"The types file will have a 1:1 mapping with the CSV data file entries, specifying the data type for each entry in alignment with the GlueSQL conventions.")))))}g.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/6ba4a510.b8825408.js b/docs/0.16.0/assets/js/6ba4a510.b8825408.js new file mode 100644 index 00000000..55c6155d --- /dev/null +++ b/docs/0.16.0/assets/js/6ba4a510.b8825408.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[3117],{5680:(e,n,t)=>{t.d(n,{xA:()=>c,yg:()=>y});var a=t(6540);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function l(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function s(e){for(var n=1;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var o=a.createContext({}),u=function(e){var n=a.useContext(o),t=n;return e&&(t="function"==typeof e?e(n):s(s({},n),e)),t},c=function(e){var n=u(e.components);return a.createElement(o.Provider,{value:n},e.children)},p="mdxType",m={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},g=a.forwardRef((function(e,n){var t=e.components,r=e.mdxType,l=e.originalType,o=e.parentName,c=i(e,["components","mdxType","originalType","parentName"]),p=u(t),g=r,y=p["".concat(o,".").concat(g)]||p[g]||m[g]||l;return t?a.createElement(y,s(s({ref:n},c),{},{components:t})):a.createElement(y,s({ref:n},c))}));function y(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var l=t.length,s=new Array(l);s[0]=g;var i={};for(var o in n)hasOwnProperty.call(n,o)&&(i[o]=n[o]);i.originalType=e,i[p]="string"==typeof e?e:r,s[1]=i;for(var u=2;u{t.r(n),t.d(n,{assets:()=>o,contentTitle:()=>s,default:()=>m,frontMatter:()=>l,metadata:()=>i,toc:()=>u});var a=t(8168),r=(t(6540),t(5680));const l={},s="ACOS",i={unversionedId:"sql-syntax/functions/math/acos",id:"sql-syntax/functions/math/acos",title:"ACOS",description:"The ACOS function is used to calculate the arccosine (inverse cosine) of a number. It takes a single numeric argument, which should be a float value in the range of -1 to 1, and returns the arccosine of that number in radians.",source:"@site/docs/sql-syntax/functions/math/acos.md",sourceDirName:"sql-syntax/functions/math",slug:"/sql-syntax/functions/math/acos",permalink:"/docs/0.16.0/sql-syntax/functions/math/acos",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"ABS",permalink:"/docs/0.16.0/sql-syntax/functions/math/abs"},next:{title:"ASIN",permalink:"/docs/0.16.0/sql-syntax/functions/math/asin"}},o={},u=[{value:"Syntax",id:"syntax",level:2},{value:"Examples",id:"examples",level:2},{value:"Example 1: Using ACOS with float values",id:"example-1-using-acos-with-float-values",level:3},{value:"Example 2: Using ACOS with NULL values",id:"example-2-using-acos-with-null-values",level:3},{value:"Errors",id:"errors",level:2},{value:"Example 3: Using ACOS with non-numeric values",id:"example-3-using-acos-with-non-numeric-values",level:3},{value:"Example 4: Using ACOS with multiple arguments",id:"example-4-using-acos-with-multiple-arguments",level:3}],c={toc:u},p="wrapper";function m(e){let{components:n,...t}=e;return(0,r.yg)(p,(0,a.A)({},c,t,{components:n,mdxType:"MDXLayout"}),(0,r.yg)("h1",{id:"acos"},"ACOS"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"ACOS")," function is used to calculate the arccosine (inverse cosine) of a number. It takes a single numeric argument, which should be a float value in the range of -1 to 1, and returns the arccosine of that number in radians."),(0,r.yg)("h2",{id:"syntax"},"Syntax"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"ACOS(value)\n")),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"value"),": A numeric expression for which the arccosine is to be calculated. The value should be in the range of -1 to 1.")),(0,r.yg)("h2",{id:"examples"},"Examples"),(0,r.yg)("p",null,"Let's consider a table named ",(0,r.yg)("inlineCode",{parentName:"p"},"SingleItem")," with the following schema:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE SingleItem (id INTEGER);\n")),(0,r.yg)("p",null,"Insert a row into the ",(0,r.yg)("inlineCode",{parentName:"p"},"SingleItem")," table:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO SingleItem VALUES (0);\n")),(0,r.yg)("h3",{id:"example-1-using-acos-with-float-values"},"Example 1: Using ACOS with float values"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT ACOS(0.5) AS acos1, ACOS(1) AS acos2 FROM SingleItem;\n")),(0,r.yg)("p",null,"Result:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre"}," acos1 | acos2\n----------------+---------------\n 1.0471975511966 | 0.0\n")),(0,r.yg)("h3",{id:"example-2-using-acos-with-null-values"},"Example 2: Using ACOS with NULL values"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT ACOS(NULL) AS acos FROM SingleItem;\n")),(0,r.yg)("p",null,"Result:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre"}," acos\n-------\n (null)\n")),(0,r.yg)("h2",{id:"errors"},"Errors"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"ACOS")," function requires a numeric value in the range of -1 to 1 as its argument. Using non-numeric values or more than one argument will result in an error."),(0,r.yg)("h3",{id:"example-3-using-acos-with-non-numeric-values"},"Example 3: Using ACOS with non-numeric values"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT ACOS('string') AS acos FROM SingleItem;\n")),(0,r.yg)("p",null,"Error: Function requires a numeric value."),(0,r.yg)("h3",{id:"example-4-using-acos-with-multiple-arguments"},"Example 4: Using ACOS with multiple arguments"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT ACOS(1.0, 2.0) AS acos FROM SingleItem;\n")),(0,r.yg)("p",null,"Error: Function expects 1 argument, but 2 were provided."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/6c5232c2.fafd0f71.js b/docs/0.16.0/assets/js/6c5232c2.fafd0f71.js new file mode 100644 index 00000000..939ad2ef --- /dev/null +++ b/docs/0.16.0/assets/js/6c5232c2.fafd0f71.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[7135],{5680:(e,t,a)=>{a.d(t,{xA:()=>u,yg:()=>y});var n=a(6540);function l(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function i(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function r(e){for(var t=1;t=0||(l[a]=e[a]);return l}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(l[a]=e[a])}return l}var s=n.createContext({}),d=function(e){var t=n.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):r(r({},t),e)),a},u=function(e){var t=d(e.components);return n.createElement(s.Provider,{value:t},e.children)},p="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var a=e.components,l=e.mdxType,i=e.originalType,s=e.parentName,u=o(e,["components","mdxType","originalType","parentName"]),p=d(a),m=l,y=p["".concat(s,".").concat(m)]||p[m]||c[m]||i;return a?n.createElement(y,r(r({ref:t},u),{},{components:a})):n.createElement(y,r({ref:t},u))}));function y(e,t){var a=arguments,l=t&&t.mdxType;if("string"==typeof e||l){var i=a.length,r=new Array(i);r[0]=m;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[p]="string"==typeof e?e:l,r[1]=o;for(var d=2;d{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>r,default:()=>c,frontMatter:()=>i,metadata:()=>o,toc:()=>d});var n=a(8168),l=(a(6540),a(5680));const i={sidebar_position:2},r="Data Dictionary",o={unversionedId:"sql-syntax/statements/metadata/data-dictionary",id:"sql-syntax/statements/metadata/data-dictionary",title:"Data Dictionary",description:"In GlueSQL, there are predefined tables, also known as Data Dictionary tables, which store metadata about the database objects like tables, columns, and indexes. These tables can be queried like any other table in the database, and they provide useful information about the database schema.",source:"@site/docs/sql-syntax/statements/metadata/data-dictionary.md",sourceDirName:"sql-syntax/statements/metadata",slug:"/sql-syntax/statements/metadata/data-dictionary",permalink:"/docs/0.16.0/sql-syntax/statements/metadata/data-dictionary",draft:!1,tags:[],version:"current",sidebarPosition:2,frontMatter:{sidebar_position:2},sidebar:"autoSidebar",previous:{title:"SHOW TABLES",permalink:"/docs/0.16.0/sql-syntax/statements/metadata/show-tables"},next:{title:"BOOLEAN",permalink:"/docs/0.16.0/sql-syntax/data-types/boolean"}},s={},d=[{value:"GLUE_TABLES",id:"glue_tables",level:2},{value:"GLUE_TABLE_COLUMNS",id:"glue_table_columns",level:2},{value:"GLUE_INDEXES",id:"glue_indexes",level:2},{value:"Examples",id:"examples",level:2}],u={toc:d},p="wrapper";function c(e){let{components:t,...a}=e;return(0,l.yg)(p,(0,n.A)({},u,a,{components:t,mdxType:"MDXLayout"}),(0,l.yg)("h1",{id:"data-dictionary"},"Data Dictionary"),(0,l.yg)("p",null,"In GlueSQL, there are predefined tables, also known as Data Dictionary tables, which store metadata about the database objects like tables, columns, and indexes. These tables can be queried like any other table in the database, and they provide useful information about the database schema."),(0,l.yg)("p",null,"The Data Dictionary tables in GlueSQL include:"),(0,l.yg)("ol",null,(0,l.yg)("li",{parentName:"ol"},(0,l.yg)("inlineCode",{parentName:"li"},"GLUE_TABLES")),(0,l.yg)("li",{parentName:"ol"},(0,l.yg)("inlineCode",{parentName:"li"},"GLUE_TABLE_COLUMNS")),(0,l.yg)("li",{parentName:"ol"},(0,l.yg)("inlineCode",{parentName:"li"},"GLUE_INDEXES"))),(0,l.yg)("p",null,"Please note that the columns provided in these tables are the default columns. Storage implementations may provide additional information in these tables."),(0,l.yg)("h2",{id:"glue_tables"},"GLUE_TABLES"),(0,l.yg)("p",null,"The ",(0,l.yg)("inlineCode",{parentName:"p"},"GLUE_TABLES")," table contains a list of all tables in the database."),(0,l.yg)("p",null,"Columns:"),(0,l.yg)("ul",null,(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("inlineCode",{parentName:"li"},"TABLE_NAME"),": The name of the table.")),(0,l.yg)("h2",{id:"glue_table_columns"},"GLUE_TABLE_COLUMNS"),(0,l.yg)("p",null,"The ",(0,l.yg)("inlineCode",{parentName:"p"},"GLUE_TABLE_COLUMNS")," table contains information about the columns in each table."),(0,l.yg)("p",null,"Columns:"),(0,l.yg)("ul",null,(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("inlineCode",{parentName:"li"},"TABLE_NAME"),": The name of the table that the column belongs to."),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("inlineCode",{parentName:"li"},"COLUMN_NAME"),": The name of the column."),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("inlineCode",{parentName:"li"},"COLUMN_ID"),": The column's unique identifier.")),(0,l.yg)("h2",{id:"glue_indexes"},"GLUE_INDEXES"),(0,l.yg)("p",null,"The ",(0,l.yg)("inlineCode",{parentName:"p"},"GLUE_INDEXES")," table contains information about the indexes defined in the database."),(0,l.yg)("p",null,"Columns:"),(0,l.yg)("ul",null,(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("inlineCode",{parentName:"li"},"TABLE_NAME"),": The name of the table that the index belongs to."),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("inlineCode",{parentName:"li"},"INDEX_NAME"),": The name of the index."),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("inlineCode",{parentName:"li"},"ORDER"),': The order in which the index is sorted (e.g., "ASC", "DESC", or "BOTH").'),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("inlineCode",{parentName:"li"},"EXPRESSION"),': The expression used for the indexed column (e.g., "id" or "id + 2").'),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("inlineCode",{parentName:"li"},"UNIQUENESS"),": A boolean value indicating whether the index enforces uniqueness.")),(0,l.yg)("h2",{id:"examples"},"Examples"),(0,l.yg)("p",null,"To query the ",(0,l.yg)("inlineCode",{parentName:"p"},"GLUE_TABLES")," table and get a list of all tables in the database:"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT * FROM GLUE_TABLES;\n")),(0,l.yg)("p",null,"To query the ",(0,l.yg)("inlineCode",{parentName:"p"},"GLUE_TABLE_COLUMNS")," table and get information about the columns in each table:"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT * FROM GLUE_TABLE_COLUMNS;\n")),(0,l.yg)("p",null,"To query the ",(0,l.yg)("inlineCode",{parentName:"p"},"GLUE_INDEXES")," table and get information about the indexes defined in the database:"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT * FROM GLUE_INDEXES;\n")))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/6d2a6c9a.899740c3.js b/docs/0.16.0/assets/js/6d2a6c9a.899740c3.js new file mode 100644 index 00000000..3ed9247e --- /dev/null +++ b/docs/0.16.0/assets/js/6d2a6c9a.899740c3.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[285],{644:e=>{e.exports=JSON.parse('{"permalink":"/docs/0.16.0/blog/tags/query-interface","page":1,"postsPerPage":10,"totalPages":1,"totalCount":1,"blogDescription":"Blog","blogTitle":"Blog"}')}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/6e772156.de8699ba.js b/docs/0.16.0/assets/js/6e772156.de8699ba.js new file mode 100644 index 00000000..8a6d9d9d --- /dev/null +++ b/docs/0.16.0/assets/js/6e772156.de8699ba.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[108],{5680:(e,t,r)=>{r.d(t,{xA:()=>u,yg:()=>d});var n=r(6540);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var p=n.createContext({}),l=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},u=function(e){var t=l(e.components);return n.createElement(p.Provider,{value:t},e.children)},c="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},g=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),c=l(r),g=a,d=c["".concat(p,".").concat(g)]||c[g]||m[g]||o;return r?n.createElement(d,i(i({ref:t},u),{},{components:r})):n.createElement(d,i({ref:t},u))}));function d(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,i=new Array(o);i[0]=g;var s={};for(var p in t)hasOwnProperty.call(t,p)&&(s[p]=t[p]);s.originalType=e,s[c]="string"==typeof e?e:a,i[1]=s;for(var l=2;l{r.r(t),r.d(t,{assets:()=>p,contentTitle:()=>i,default:()=>m,frontMatter:()=>o,metadata:()=>s,toc:()=>l});var n=r(8168),a=(r(6540),r(5680));const o={},i="Memory Storage",s={unversionedId:"storages/supported-storages/memory-storage",id:"storages/supported-storages/memory-storage",title:"Memory Storage",description:"MemoryStorage is a foundational storage option designed for in-memory, non-persistent data. Despite its simplicity, it is robust enough for use in production environments.",source:"@site/docs/storages/supported-storages/memory-storage.md",sourceDirName:"storages/supported-storages",slug:"/storages/supported-storages/memory-storage",permalink:"/docs/0.16.0/storages/supported-storages/memory-storage",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"JSON Storage",permalink:"/docs/0.16.0/storages/supported-storages/json-storage"},next:{title:"Parquet Storage",permalink:"/docs/0.16.0/storages/supported-storages/parquet-storage"}},p={},l=[],u={toc:l},c="wrapper";function m(e){let{components:t,...r}=e;return(0,a.yg)(c,(0,n.A)({},u,r,{components:t,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"memory-storage"},"Memory Storage"),(0,a.yg)("p",null,"MemoryStorage is a foundational storage option designed for in-memory, non-persistent data. Despite its simplicity, it is robust enough for use in production environments."),(0,a.yg)("p",null,"A key aspect of MemoryStorage is not only its functionality but also its role as an exemplary case showcasing how simple it is to develop custom storage in GlueSQL. It provides a practical demonstration of what a minimalistic, yet fully functional storage interface can look like in GlueSQL."),(0,a.yg)("p",null,"MemoryStorage is accessible across multiple environments, including Rust, Rust (WASM), JavaScript (Web), and Node.js."),(0,a.yg)("p",null,"The storage interface is implemented with the following traits: ",(0,a.yg)("inlineCode",{parentName:"p"},"Store"),", ",(0,a.yg)("inlineCode",{parentName:"p"},"StoreMut"),", ",(0,a.yg)("inlineCode",{parentName:"p"},"AlterTable"),", ",(0,a.yg)("inlineCode",{parentName:"p"},"CustomFunction"),", ",(0,a.yg)("inlineCode",{parentName:"p"},"CustomFunctionMut"),", and ",(0,a.yg)("inlineCode",{parentName:"p"},"Metadata"),"."),(0,a.yg)("p",null,"Consider the Rust code structure for MemoryStorage:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-rust"},"#[derive(Debug, Clone, Serialize, Deserialize)]\npub struct Item {\n pub schema: Schema,\n pub rows: BTreeMap,\n}\n\n#[derive(Debug, Clone, Serialize, Deserialize, Default)]\npub struct MemoryStorage {\n pub id_counter: i64,\n pub items: HashMap,\n pub metadata: HashMap>,\n pub functions: HashMap,\n}\n")),(0,a.yg)("p",null,"This structure defines the ",(0,a.yg)("inlineCode",{parentName:"p"},"Item")," and ",(0,a.yg)("inlineCode",{parentName:"p"},"MemoryStorage")," structs. ",(0,a.yg)("inlineCode",{parentName:"p"},"Item")," struct holds the schema and rows, while ",(0,a.yg)("inlineCode",{parentName:"p"},"MemoryStorage")," struct consists of ",(0,a.yg)("inlineCode",{parentName:"p"},"id_counter")," (to keep track of the row IDs), ",(0,a.yg)("inlineCode",{parentName:"p"},"items")," (to store the actual data), ",(0,a.yg)("inlineCode",{parentName:"p"},"metadata")," (to keep metadata), and ",(0,a.yg)("inlineCode",{parentName:"p"},"functions")," (to store custom functions)."),(0,a.yg)("p",null,"Below are the implementations of the ",(0,a.yg)("inlineCode",{parentName:"p"},"Store")," and ",(0,a.yg)("inlineCode",{parentName:"p"},"StoreMut")," traits for ",(0,a.yg)("inlineCode",{parentName:"p"},"MemoryStorage"),":"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-rust"},"#[async_trait(?Send)]\nimpl Store for MemoryStorage {\n // Code for fetching schemas and data\n}\n\n#[async_trait(?Send)]\nimpl StoreMut for MemoryStorage {\n // Code for manipulating schemas and data\n}\n")),(0,a.yg)("p",null,"The Store trait implementation provides methods for fetching all schemas, fetching a specific schema, fetching data from a specific table with a given key, and scanning all data from a particular table."),(0,a.yg)("p",null,"On the other hand, the StoreMut trait implementation provides methods for inserting a new schema, deleting an existing schema, appending data to a table, inserting data into a table with a specific key, and deleting data from a table with given keys."),(0,a.yg)("p",null,"In summary, the MemoryStorage structure in GlueSQL is a straightforward yet powerful tool that elegantly showcases how simple it is to create a custom storage system. It's a testament to the power and flexibility of GlueSQL's design and the ease of implementing robust storage solutions with it."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/6ff6e7c9.34518733.js b/docs/0.16.0/assets/js/6ff6e7c9.34518733.js new file mode 100644 index 00000000..45634ea4 --- /dev/null +++ b/docs/0.16.0/assets/js/6ff6e7c9.34518733.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[1747],{5680:(e,n,t)=>{t.d(n,{xA:()=>u,yg:()=>d});var a=t(6540);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function i(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function l(e){for(var n=1;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var s=a.createContext({}),p=function(e){var n=a.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):l(l({},n),e)),t},u=function(e){var n=p(e.components);return a.createElement(s.Provider,{value:n},e.children)},N="mdxType",y={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},T=a.forwardRef((function(e,n){var t=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,u=o(e,["components","mdxType","originalType","parentName"]),N=p(t),T=r,d=N["".concat(s,".").concat(T)]||N[T]||y[T]||i;return t?a.createElement(d,l(l({ref:n},u),{},{components:t})):a.createElement(d,l({ref:n},u))}));function d(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var i=t.length,l=new Array(i);l[0]=T;var o={};for(var s in n)hasOwnProperty.call(n,s)&&(o[s]=n[s]);o.originalType=e,o[N]="string"==typeof e?e:r,l[1]=o;for(var p=2;p{t.r(n),t.d(n,{assets:()=>s,contentTitle:()=>l,default:()=>y,frontMatter:()=>i,metadata:()=>o,toc:()=>p});var a=t(8168),r=(t(6540),t(5680));const i={sidebar_position:9},l="INTERVAL",o={unversionedId:"sql-syntax/data-types/interval",id:"sql-syntax/data-types/interval",title:"INTERVAL",description:"The INTERVAL data type in GlueSQL is used to represent a period of time. In accordance with the ANSI SQL standard, several subtypes of INTERVAL can be used to represent different units of time, such as years, months, days, hours, minutes, and seconds. These subtypes are:",source:"@site/docs/sql-syntax/data-types/interval.md",sourceDirName:"sql-syntax/data-types",slug:"/sql-syntax/data-types/interval",permalink:"/docs/0.16.0/sql-syntax/data-types/interval",draft:!1,tags:[],version:"current",sidebarPosition:9,frontMatter:{sidebar_position:9},sidebar:"autoSidebar",previous:{title:"TIME",permalink:"/docs/0.16.0/sql-syntax/data-types/time"},next:{title:"LIST",permalink:"/docs/0.16.0/sql-syntax/data-types/list"}},s={},p=[{value:"Creating a Table with INTERVAL Columns",id:"creating-a-table-with-interval-columns",level:2},{value:"Inserting INTERVAL Values",id:"inserting-interval-values",level:2},{value:"INTERVAL Subtypes and Syntax",id:"interval-subtypes-and-syntax",level:2},{value:"Unsupported Conversions",id:"unsupported-conversions",level:2},{value:"Conclusion",id:"conclusion",level:2}],u={toc:p},N="wrapper";function y(e){let{components:n,...t}=e;return(0,r.yg)(N,(0,a.A)({},u,t,{components:n,mdxType:"MDXLayout"}),(0,r.yg)("h1",{id:"interval"},"INTERVAL"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"INTERVAL")," data type in GlueSQL is used to represent a period of time. In accordance with the ANSI SQL standard, several subtypes of ",(0,r.yg)("inlineCode",{parentName:"p"},"INTERVAL")," can be used to represent different units of time, such as years, months, days, hours, minutes, and seconds. These subtypes are:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"YEAR"),(0,r.yg)("li",{parentName:"ul"},"YEAR TO MONTH"),(0,r.yg)("li",{parentName:"ul"},"MONTH"),(0,r.yg)("li",{parentName:"ul"},"DAY"),(0,r.yg)("li",{parentName:"ul"},"DAY TO HOUR"),(0,r.yg)("li",{parentName:"ul"},"DAY TO MINUTE"),(0,r.yg)("li",{parentName:"ul"},"DAY TO SECOND"),(0,r.yg)("li",{parentName:"ul"},"HOUR"),(0,r.yg)("li",{parentName:"ul"},"HOUR TO MINUTE"),(0,r.yg)("li",{parentName:"ul"},"HOUR TO SECOND"),(0,r.yg)("li",{parentName:"ul"},"MINUTE"),(0,r.yg)("li",{parentName:"ul"},"MINUTE TO SECOND"),(0,r.yg)("li",{parentName:"ul"},"SECOND")),(0,r.yg)("h2",{id:"creating-a-table-with-interval-columns"},"Creating a Table with INTERVAL Columns"),(0,r.yg)("p",null,"To create a table with ",(0,r.yg)("inlineCode",{parentName:"p"},"INTERVAL")," columns, simply use the ",(0,r.yg)("inlineCode",{parentName:"p"},"INTERVAL")," keyword for the data type:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE IntervalLog (\n id INTEGER,\n interval1 INTERVAL,\n interval2 INTERVAL\n);\n")),(0,r.yg)("h2",{id:"inserting-interval-values"},"Inserting INTERVAL Values"),(0,r.yg)("p",null,"To insert ",(0,r.yg)("inlineCode",{parentName:"p"},"INTERVAL")," values into a table, use the ",(0,r.yg)("inlineCode",{parentName:"p"},"INTERVAL")," keyword followed by a string literal representing the interval value:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO IntervalLog VALUES\n (1, INTERVAL '1-2' YEAR TO MONTH, INTERVAL 30 MONTH),\n (2, INTERVAL 12 DAY, INTERVAL '35' HOUR),\n (3, INTERVAL '12' MINUTE, INTERVAL 300 SECOND),\n (4, INTERVAL '-3 14' DAY TO HOUR, INTERVAL '3 12:30' DAY TO MINUTE),\n (5, INTERVAL '3 14:00:00' DAY TO SECOND, INTERVAL '3 12:30:12.1324' DAY TO SECOND),\n (6, INTERVAL '12:00' HOUR TO MINUTE, INTERVAL '-12:30:12' HOUR TO SECOND),\n (7, INTERVAL '-1000-11' YEAR TO MONTH, INTERVAL '-30:11' MINUTE TO SECOND);\n")),(0,r.yg)("h2",{id:"interval-subtypes-and-syntax"},"INTERVAL Subtypes and Syntax"),(0,r.yg)("p",null,"Here are some examples of how to use different ",(0,r.yg)("inlineCode",{parentName:"p"},"INTERVAL")," subtypes:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"YEAR: ",(0,r.yg)("inlineCode",{parentName:"li"},"INTERVAL '5' YEAR")),(0,r.yg)("li",{parentName:"ul"},"YEAR TO MONTH: ",(0,r.yg)("inlineCode",{parentName:"li"},"INTERVAL '5-3' YEAR TO MONTH")),(0,r.yg)("li",{parentName:"ul"},"MONTH: ",(0,r.yg)("inlineCode",{parentName:"li"},"INTERVAL '6' MONTH")),(0,r.yg)("li",{parentName:"ul"},"DAY: ",(0,r.yg)("inlineCode",{parentName:"li"},"INTERVAL '7' DAY")),(0,r.yg)("li",{parentName:"ul"},"DAY TO HOUR: ",(0,r.yg)("inlineCode",{parentName:"li"},"INTERVAL '2 12' DAY TO HOUR")),(0,r.yg)("li",{parentName:"ul"},"DAY TO MINUTE: ",(0,r.yg)("inlineCode",{parentName:"li"},"INTERVAL '2 12:30' DAY TO MINUTE")),(0,r.yg)("li",{parentName:"ul"},"DAY TO SECOND: ",(0,r.yg)("inlineCode",{parentName:"li"},"INTERVAL '2 12:30:45' DAY TO SECOND")),(0,r.yg)("li",{parentName:"ul"},"HOUR: ",(0,r.yg)("inlineCode",{parentName:"li"},"INTERVAL '18' HOUR")),(0,r.yg)("li",{parentName:"ul"},"HOUR TO MINUTE: ",(0,r.yg)("inlineCode",{parentName:"li"},"INTERVAL '18:30' HOUR TO MINUTE")),(0,r.yg)("li",{parentName:"ul"},"HOUR TO SECOND: ",(0,r.yg)("inlineCode",{parentName:"li"},"INTERVAL '18:30:45' HOUR TO SECOND")),(0,r.yg)("li",{parentName:"ul"},"MINUTE: ",(0,r.yg)("inlineCode",{parentName:"li"},"INTERVAL '45' MINUTE")),(0,r.yg)("li",{parentName:"ul"},"MINUTE TO SECOND: ",(0,r.yg)("inlineCode",{parentName:"li"},"INTERVAL '45:30' MINUTE TO SECOND")),(0,r.yg)("li",{parentName:"ul"},"SECOND: ",(0,r.yg)("inlineCode",{parentName:"li"},"INTERVAL '30' SECOND"))),(0,r.yg)("h2",{id:"unsupported-conversions"},"Unsupported Conversions"),(0,r.yg)("p",null,"In GlueSQL, you cannot convert between different ",(0,r.yg)("inlineCode",{parentName:"p"},"INTERVAL")," subtypes, such as converting 1 MONTH to DAYS or converting YEAR TO MONTH to DAY TO SECOND. These conversions are not supported."),(0,r.yg)("h2",{id:"conclusion"},"Conclusion"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"INTERVAL")," data type is a powerful way to represent time periods in GlueSQL. By following the ANSI SQL standard, you can use a combination of subtypes to represent complex periods of time. Use the ",(0,r.yg)("inlineCode",{parentName:"p"},"INTERVAL")," keyword when creating tables and inserting values to make the most of this data type."))}y.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/723607d1.e3c765d2.js b/docs/0.16.0/assets/js/723607d1.e3c765d2.js new file mode 100644 index 00000000..c8f35b0b --- /dev/null +++ b/docs/0.16.0/assets/js/723607d1.e3c765d2.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[7297],{2095:o=>{o.exports=JSON.parse('{"permalink":"/docs/0.16.0/blog/tags/documentation","page":1,"postsPerPage":10,"totalPages":1,"totalCount":1,"blogDescription":"Blog","blogTitle":"Blog"}')}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/72c409f7.37981358.js b/docs/0.16.0/assets/js/72c409f7.37981358.js new file mode 100644 index 00000000..568faadc --- /dev/null +++ b/docs/0.16.0/assets/js/72c409f7.37981358.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[4229],{5680:(e,t,r)=>{r.d(t,{xA:()=>g,yg:()=>y});var n=r(6540);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function l(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var s=n.createContext({}),u=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):l(l({},t),e)),r},g=function(e){var t=u(e.components);return n.createElement(s.Provider,{value:t},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},c=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,g=i(e,["components","mdxType","originalType","parentName"]),d=u(r),c=a,y=d["".concat(s,".").concat(c)]||d[c]||p[c]||o;return r?n.createElement(y,l(l({ref:t},g),{},{components:r})):n.createElement(y,l({ref:t},g))}));function y(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,l=new Array(o);l[0]=c;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i[d]="string"==typeof e?e:a,l[1]=i;for(var u=2;u{r.r(t),r.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>p,frontMatter:()=>o,metadata:()=>i,toc:()=>u});var n=r(8168),a=(r(6540),r(5680));const o={sidebar_position:1},l="Rust",i={unversionedId:"getting-started/rust",id:"getting-started/rust",title:"Rust",description:"To install and use GlueSQL in your Rust project, you'll first need to add it as a dependency from crates.io. You can do this by adding the following lines to your Cargo.toml file:",source:"@site/docs/getting-started/rust.md",sourceDirName:"getting-started",slug:"/getting-started/rust",permalink:"/docs/0.16.0/getting-started/rust",draft:!1,tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"autoSidebar",previous:{title:"Introduction",permalink:"/docs/0.16.0/"},next:{title:"JavaScript (Web Browser)",permalink:"/docs/0.16.0/getting-started/javascript-web"}},s={},u=[],g={toc:u},d="wrapper";function p(e){let{components:t,...r}=e;return(0,a.yg)(d,(0,n.A)({},g,r,{components:t,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"rust"},"Rust"),(0,a.yg)("p",null,"To install and use GlueSQL in your Rust project, you'll first need to add it as a dependency from crates.io. You can do this by adding the following lines to your ",(0,a.yg)("inlineCode",{parentName:"p"},"Cargo.toml")," file:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-toml"},'[dependencies]\ngluesql = "0.15"\n')),(0,a.yg)("p",null,"By default, all available storage features are included with GlueSQL. Here's a list of the available features:"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"gluesql_sled_storage")," - Storage based on the persistent key-value database called sled"),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"gluesql_memory_storage")," - Simple in-memory storage"),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"gluesql-shared-memory-storage")," - A wrapper around memory-storage for easy use in multi-threaded environments"),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"gluesql-json-storage")," - Storage that allows you to analyze and modify JSON or JSONL files using SQL"),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"gluesql-composite-storage")," - A storage feature that enables joining and processing data from multiple storage types simultaneously"),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"gluesql-web-storage")," - Storage supporting localStorage and sessionStorage, available only in web assembly builds"),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"gluesql-idb-storage")," - IndexedDB-based storage, available only in web assembly builds")),(0,a.yg)("p",null,"If you don't need all the default storage features, you can disable them and select only the ones you require. To do this, update your ",(0,a.yg)("inlineCode",{parentName:"p"},"Cargo.toml")," file with the following lines:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-toml"},'[dependencies.gluesql]\nversion = "0.15"\ndefault-features = false\nfeatures = ["gluesql_memory_storage", "gluesql-json-storage"]\n')),(0,a.yg)("p",null,"This configuration will disable the default storage features and only include the ",(0,a.yg)("inlineCode",{parentName:"p"},"gluesql_memory_storage")," and ",(0,a.yg)("inlineCode",{parentName:"p"},"gluesql-json-storage")," features in your project."))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/7310a4fe.cb7c0f12.js b/docs/0.16.0/assets/js/7310a4fe.cb7c0f12.js new file mode 100644 index 00000000..b9785dc3 --- /dev/null +++ b/docs/0.16.0/assets/js/7310a4fe.cb7c0f12.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[3826],{5680:(e,a,t)=>{t.d(a,{xA:()=>m,yg:()=>d});var n=t(6540);function r(e,a,t){return a in e?Object.defineProperty(e,a,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[a]=t,e}function l(e,a){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);a&&(n=n.filter((function(a){return Object.getOwnPropertyDescriptor(e,a).enumerable}))),t.push.apply(t,n)}return t}function s(e){for(var a=1;a=0||(r[t]=e[t]);return r}(e,a);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var o=n.createContext({}),p=function(e){var a=n.useContext(o),t=a;return e&&(t="function"==typeof e?e(a):s(s({},a),e)),t},m=function(e){var a=p(e.components);return n.createElement(o.Provider,{value:a},e.children)},g="mdxType",c={inlineCode:"code",wrapper:function(e){var a=e.children;return n.createElement(n.Fragment,{},a)}},u=n.forwardRef((function(e,a){var t=e.components,r=e.mdxType,l=e.originalType,o=e.parentName,m=i(e,["components","mdxType","originalType","parentName"]),g=p(t),u=r,d=g["".concat(o,".").concat(u)]||g[u]||c[u]||l;return t?n.createElement(d,s(s({ref:a},m),{},{components:t})):n.createElement(d,s({ref:a},m))}));function d(e,a){var t=arguments,r=a&&a.mdxType;if("string"==typeof e||r){var l=t.length,s=new Array(l);s[0]=u;var i={};for(var o in a)hasOwnProperty.call(a,o)&&(i[o]=a[o]);i.originalType=e,i[g]="string"==typeof e?e:r,s[1]=i;for(var p=2;p{t.r(a),t.d(a,{assets:()=>o,contentTitle:()=>s,default:()=>c,frontMatter:()=>l,metadata:()=>i,toc:()=>p});var n=t(8168),r=(t(6540),t(5680));const l={title:"Schemaless Data",sidebar_position:5},s="Querying Schemaless Data",i={unversionedId:"sql-syntax/statements/querying/schemaless",id:"sql-syntax/statements/querying/schemaless",title:"Schemaless Data",description:"GlueSQL is an SQL database that provides a unique feature: it allows you to work with schemaless data, similar to NoSQL databases. Please note this point in the documentation.",source:"@site/docs/sql-syntax/statements/querying/schemaless.md",sourceDirName:"sql-syntax/statements/querying",slug:"/sql-syntax/statements/querying/schemaless",permalink:"/docs/0.16.0/sql-syntax/statements/querying/schemaless",draft:!1,tags:[],version:"current",sidebarPosition:5,frontMatter:{title:"Schemaless Data",sidebar_position:5},sidebar:"autoSidebar",previous:{title:"Aggregation",permalink:"/docs/0.16.0/sql-syntax/statements/querying/aggregation"},next:{title:"CREATE TABLE",permalink:"/docs/0.16.0/sql-syntax/statements/data-definition/create-table"}},o={},p=[{value:"Creating a Schemaless Table",id:"creating-a-schemaless-table",level:2},{value:"Example SQL Queries",id:"example-sql-queries",level:2},{value:"Creating Tables",id:"creating-tables",level:3},{value:"Inserting Data",id:"inserting-data",level:3},{value:"Selecting Data",id:"selecting-data",level:3},{value:"Updating Data",id:"updating-data",level:3},{value:"Selecting with Aliases and Joins",id:"selecting-with-aliases-and-joins",level:3},{value:"Notable Exception Cases",id:"notable-exception-cases",level:2},{value:"Inserting Invalid Data",id:"inserting-invalid-data",level:3},{value:"Selecting Invalid Data",id:"selecting-invalid-data",level:3}],m={toc:p},g="wrapper";function c(e){let{components:a,...t}=e;return(0,r.yg)(g,(0,n.A)({},m,t,{components:a,mdxType:"MDXLayout"}),(0,r.yg)("h1",{id:"querying-schemaless-data"},"Querying Schemaless Data"),(0,r.yg)("p",null,"GlueSQL is an SQL database that provides a unique feature: it allows you to work with schemaless data, similar to NoSQL databases. Please note this point in the documentation."),(0,r.yg)("h2",{id:"creating-a-schemaless-table"},"Creating a Schemaless Table"),(0,r.yg)("p",null,"To create a schemaless table, you don't need to specify columns when creating the table. For example:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE Sample;\n")),(0,r.yg)("p",null,"This creates a schemaless table. You can now insert data freely into each row, like a NoSQL database. Nested data is also supported."),(0,r.yg)("h2",{id:"example-sql-queries"},"Example SQL Queries"),(0,r.yg)("p",null,"Here are some example SQL queries that demonstrate how to use GlueSQL with schemaless data:"),(0,r.yg)("h3",{id:"creating-tables"},"Creating Tables"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE Player;\nCREATE TABLE Item;\n")),(0,r.yg)("h3",{id:"inserting-data"},"Inserting Data"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},'INSERT INTO Player VALUES (\'{"id": 1001, "name": "Beam", "flag": 1}\'), (\'{"id": 1002, "name": "Seo"}\');\nINSERT INTO Item VALUES (\'{"id": 100, "name": "Test 001", "dex": 324, "rare": false, "obj": {"cost": 3000}}\'), (\'{"id": 200}\');\n')),(0,r.yg)("h3",{id:"selecting-data"},"Selecting Data"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT name, dex, rare FROM Item WHERE id = 100;\nSELECT name, dex, rare FROM Item;\nSELECT * FROM Item;\n")),(0,r.yg)("h3",{id:"updating-data"},"Updating Data"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"DELETE FROM Item WHERE id > 100;\nUPDATE Item SET id = id + 1, rare = NOT rare;\nUPDATE Item SET new_field = 'Hello';\n")),(0,r.yg)("h3",{id:"selecting-with-aliases-and-joins"},"Selecting with Aliases and Joins"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT\n Player.id AS player_id,\n Player.name AS player_name,\n Item.obj['cost'] AS item_cost\nFROM Item\nJOIN Player\nWHERE flag IS NOT NULL;\n")),(0,r.yg)("h2",{id:"notable-exception-cases"},"Notable Exception Cases"),(0,r.yg)("p",null,"Here are some example SQL queries that will raise errors, along with explanations of the issues:"),(0,r.yg)("h3",{id:"inserting-invalid-data"},"Inserting Invalid Data"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"Inserting multiple values for a schemaless row:"),(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO Item VALUES ('{\"a\": 10}', '{\"b\": true}');\n")),(0,r.yg)("p",{parentName:"li"},"Schemaless rows accept only single values.")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"Inserting data from a SELECT statement:"),(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO Item SELECT id, name FROM Item LIMIT 1;\n")),(0,r.yg)("p",{parentName:"li"},"Schemaless rows cannot be inserted using a SELECT statement.")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"Inserting a JSON array:"),(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO Item VALUES ('[1, 2, 3]');\n")),(0,r.yg)("p",{parentName:"li"},"Only JSON objects are allowed for schemaless rows.")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"Inserting a boolean value:"),(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO Item VALUES (true);\n")),(0,r.yg)("p",{parentName:"li"},"Text literals are required for schemaless rows.")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"Inserting an expression result:"),(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO Item VALUES (CAST(1 AS INTEGER) + 4);\n")),(0,r.yg)("p",{parentName:"li"},"Map or string values are required for schemaless rows.")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"Inserting data from a SELECT statement with LIMIT:"),(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO Item SELECT id FROM Item LIMIT 1;\n")),(0,r.yg)("p",{parentName:"li"},"Map type values are required for schemaless rows."))),(0,r.yg)("h3",{id:"selecting-invalid-data"},"Selecting Invalid Data"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"Using IN with a schemaless subquery:"),(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT id FROM Item WHERE id IN (SELECT * FROM Item);\n")),(0,r.yg)("p",{parentName:"li"},"Schemaless projections are not allowed for IN subqueries.")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},"Using a comparison with a schemaless subquery:"),(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT id FROM Item WHERE id = (SELECT * FROM Item LIMIT 1);\n")),(0,r.yg)("p",{parentName:"li"},"Schemaless projections are not allowed for subqueries."))))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/7457c448.8eae7baa.js b/docs/0.16.0/assets/js/7457c448.8eae7baa.js new file mode 100644 index 00000000..7b5b61bd --- /dev/null +++ b/docs/0.16.0/assets/js/7457c448.8eae7baa.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[827],{5680:(e,t,n)=>{n.d(t,{xA:()=>u,yg:()=>y});var r=n(6540);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function l(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),p=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},u=function(e){var t=p(e.components);return r.createElement(s.Provider,{value:t},e.children)},c="mdxType",g={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,s=e.parentName,u=o(e,["components","mdxType","originalType","parentName"]),c=p(n),d=a,y=c["".concat(s,".").concat(d)]||c[d]||g[d]||i;return n?r.createElement(y,l(l({ref:t},u),{},{components:n})):r.createElement(y,l({ref:t},u))}));function y(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,l=new Array(i);l[0]=d;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[c]="string"==typeof e?e:a,l[1]=o;for(var p=2;p{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>g,frontMatter:()=>i,metadata:()=>o,toc:()=>p});var r=n(8168),a=(n(6540),n(5680));const i={},l="RPAD",o={unversionedId:"sql-syntax/functions/text/rpad",id:"sql-syntax/functions/text/rpad",title:"RPAD",description:"The RPAD function in SQL pads the right side of a string with a specific set of characters.",source:"@site/docs/sql-syntax/functions/text/rpad.md",sourceDirName:"sql-syntax/functions/text",slug:"/sql-syntax/functions/text/rpad",permalink:"/docs/0.16.0/sql-syntax/functions/text/rpad",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"RIGHT",permalink:"/docs/0.16.0/sql-syntax/functions/text/right"},next:{title:"RTRIM",permalink:"/docs/0.16.0/sql-syntax/functions/text/rtrim"}},s={},p=[{value:"Syntax",id:"syntax",level:2},{value:"Parameters",id:"parameters",level:2},{value:"Return Value",id:"return-value",level:2},{value:"Errors",id:"errors",level:2},{value:"Examples",id:"examples",level:2}],u={toc:p},c="wrapper";function g(e){let{components:t,...n}=e;return(0,a.yg)(c,(0,r.A)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"rpad"},"RPAD"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"RPAD")," function in SQL pads the right side of a string with a specific set of characters."),(0,a.yg)("h2",{id:"syntax"},"Syntax"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"RPAD(string, length, pad_string)\n")),(0,a.yg)("h2",{id:"parameters"},"Parameters"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"string"),": The original string to pad."),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"length"),": The length of the resulting string after padding. If this is less than the length of the original string, the result is truncated."),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"pad_string")," (optional): The string to use for padding. If not supplied, spaces are used.")),(0,a.yg)("h2",{id:"return-value"},"Return Value"),(0,a.yg)("p",null,"The function returns a new string that is the same as the original string, but with additional padding on the right side to achieve the specified length."),(0,a.yg)("h2",{id:"errors"},"Errors"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},"If the ",(0,a.yg)("inlineCode",{parentName:"li"},"string")," argument is not a string, a ",(0,a.yg)("inlineCode",{parentName:"li"},"FunctionRequiresStringValue")," error will be returned."),(0,a.yg)("li",{parentName:"ul"},"If the ",(0,a.yg)("inlineCode",{parentName:"li"},"length")," argument is not a positive integer, a ",(0,a.yg)("inlineCode",{parentName:"li"},"FunctionRequiresUSizeValue")," error will be returned.")),(0,a.yg)("h2",{id:"examples"},"Examples"),(0,a.yg)("p",null,"Consider a table ",(0,a.yg)("inlineCode",{parentName:"p"},"Item")," created and filled with the following data:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE Item (\n name TEXT\n);\nINSERT INTO Item VALUES ('hello');\n")),(0,a.yg)("p",null,"You can use the ",(0,a.yg)("inlineCode",{parentName:"p"},"RPAD")," function to pad the ",(0,a.yg)("inlineCode",{parentName:"p"},"name")," values to a length of 10 with the character 'b':"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT RPAD(name, 10, 'b') AS padded_name FROM Item;\n")),(0,a.yg)("p",null,"This will return:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre"},"hellobbbbb\n")),(0,a.yg)("p",null,"If the ",(0,a.yg)("inlineCode",{parentName:"p"},"length")," argument is less than the length of the string, the original string will be truncated:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT RPAD(name, 3, 'b') AS padded_name FROM Item;\n")),(0,a.yg)("p",null,"This will return:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre"},"hel\n")))}g.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/7538b401.9467be0b.js b/docs/0.16.0/assets/js/7538b401.9467be0b.js new file mode 100644 index 00000000..b9099ab7 --- /dev/null +++ b/docs/0.16.0/assets/js/7538b401.9467be0b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[9309],{7560:s=>{s.exports=JSON.parse('{"label":"Documentation","permalink":"/docs/0.16.0/blog/tags/documentation","allTagsPath":"/docs/0.16.0/blog/tags","count":1}')}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/75880d90.d5ebfb17.js b/docs/0.16.0/assets/js/75880d90.d5ebfb17.js new file mode 100644 index 00000000..38ef28bf --- /dev/null +++ b/docs/0.16.0/assets/js/75880d90.d5ebfb17.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[3268],{4084:l=>{l.exports=JSON.parse('[{"label":"v0.15","permalink":"/docs/0.16.0/blog/tags/v-0-15","count":1},{"label":"release-note","permalink":"/docs/0.16.0/blog/tags/release-note","count":2},{"label":"gluesql","permalink":"/docs/0.16.0/blog/tags/gluesql","count":1},{"label":"query-interface","permalink":"/docs/0.16.0/blog/tags/query-interface","count":1},{"label":"database","permalink":"/docs/0.16.0/blog/tags/database","count":3},{"label":"proposal","permalink":"/docs/0.16.0/blog/tags/proposal","count":1},{"label":"ChatGPT","permalink":"/docs/0.16.0/blog/tags/chat-gpt","count":1},{"label":"Test-Driven-Documentation","permalink":"/docs/0.16.0/blog/tags/test-driven-documentation","count":1},{"label":"TDD","permalink":"/docs/0.16.0/blog/tags/tdd","count":1},{"label":"Documentation","permalink":"/docs/0.16.0/blog/tags/documentation","count":1},{"label":"Automation","permalink":"/docs/0.16.0/blog/tags/automation","count":1},{"label":"sql","permalink":"/docs/0.16.0/blog/tags/sql","count":1},{"label":"nosql","permalink":"/docs/0.16.0/blog/tags/nosql","count":1},{"label":"v0.14","permalink":"/docs/0.16.0/blog/tags/v-0-14","count":1}]')}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/76bcd116.31f94fcd.js b/docs/0.16.0/assets/js/76bcd116.31f94fcd.js new file mode 100644 index 00000000..f2939bc7 --- /dev/null +++ b/docs/0.16.0/assets/js/76bcd116.31f94fcd.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[6637],{8764:s=>{s.exports=JSON.parse('{"label":"proposal","permalink":"/docs/0.16.0/blog/tags/proposal","allTagsPath":"/docs/0.16.0/blog/tags","count":1}')}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/772fc39d.44e54754.js b/docs/0.16.0/assets/js/772fc39d.44e54754.js new file mode 100644 index 00000000..70ed9793 --- /dev/null +++ b/docs/0.16.0/assets/js/772fc39d.44e54754.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[6704],{5680:(e,t,a)=>{a.d(t,{xA:()=>d,yg:()=>g});var n=a(6540);function i(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function o(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function s(e){for(var t=1;t=0||(i[a]=e[a]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(i[a]=e[a])}return i}var l=n.createContext({}),u=function(e){var t=n.useContext(l),a=t;return e&&(a="function"==typeof e?e(t):s(s({},t),e)),a},d=function(e){var t=u(e.components);return n.createElement(l.Provider,{value:t},e.children)},c="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},p=n.forwardRef((function(e,t){var a=e.components,i=e.mdxType,o=e.originalType,l=e.parentName,d=r(e,["components","mdxType","originalType","parentName"]),c=u(a),p=i,g=c["".concat(l,".").concat(p)]||c[p]||h[p]||o;return a?n.createElement(g,s(s({ref:t},d),{},{components:a})):n.createElement(g,s({ref:t},d))}));function g(e,t){var a=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=a.length,s=new Array(o);s[0]=p;var r={};for(var l in t)hasOwnProperty.call(t,l)&&(r[l]=t[l]);r.originalType=e,r[c]="string"==typeof e?e:i,s[1]=r;for(var u=2;u{a.r(t),a.d(t,{assets:()=>l,contentTitle:()=>s,default:()=>h,frontMatter:()=>o,metadata:()=>r,toc:()=>u});var n=a(8168),i=(a(6540),a(5680));const o={title:"GlueSQL - Revolutionizing Databases by Unifying Query Interfaces",description:"GlueSQL - Revolutionizing Databases by Unifying Query Interfaces",slug:"revolutionizing-databases-by-unifying-query-interfaces",authors:[{name:"Taehoon Moon",title:"Creator of GlueSQL",url:"https://github.com/panarch",image_url:"https://github.com/panarch.png"}],tags:["gluesql","query-interface","database","proposal"]},s="GlueSQL: Revolutionizing Databases by Unifying Query Interfaces",r={permalink:"/docs/0.16.0/blog/revolutionizing-databases-by-unifying-query-interfaces",source:"@site/blog/2023-05-30-revolutionizing-databases-by-unifying-query-interfaces.md",title:"GlueSQL - Revolutionizing Databases by Unifying Query Interfaces",description:"GlueSQL - Revolutionizing Databases by Unifying Query Interfaces",date:"2023-05-30T00:00:00.000Z",formattedDate:"May 30, 2023",tags:[{label:"gluesql",permalink:"/docs/0.16.0/blog/tags/gluesql"},{label:"query-interface",permalink:"/docs/0.16.0/blog/tags/query-interface"},{label:"database",permalink:"/docs/0.16.0/blog/tags/database"},{label:"proposal",permalink:"/docs/0.16.0/blog/tags/proposal"}],readingTime:13.07,hasTruncateMarker:!1,authors:[{name:"Taehoon Moon",title:"Creator of GlueSQL",url:"https://github.com/panarch",image_url:"https://github.com/panarch.png",imageURL:"https://github.com/panarch.png"}],frontMatter:{title:"GlueSQL - Revolutionizing Databases by Unifying Query Interfaces",description:"GlueSQL - Revolutionizing Databases by Unifying Query Interfaces",slug:"revolutionizing-databases-by-unifying-query-interfaces",authors:[{name:"Taehoon Moon",title:"Creator of GlueSQL",url:"https://github.com/panarch",image_url:"https://github.com/panarch.png",imageURL:"https://github.com/panarch.png"}],tags:["gluesql","query-interface","database","proposal"]},prevItem:{title:"Release v0.15",permalink:"/docs/0.16.0/blog/release-v0.15"},nextItem:{title:"Test-Driven Documentation - Automating User Manual Creation in GlueSQL",permalink:"/docs/0.16.0/blog/test-driven-documentation"}},l={authorsImageUrls:[void 0]},u=[{value:"Introduction",id:"introduction",level:2},{value:"The Problem: Why Reinvent the Database?",id:"the-problem-why-reinvent-the-database",level:2},{value:"The Vision of GlueSQL",id:"the-vision-of-gluesql",level:2},{value:"Benefits to Database Users: Unifying Query Interfaces, Streamlining Software Development, and Reducing Costs",id:"benefits-to-database-users-unifying-query-interfaces-streamlining-software-development-and-reducing-costs",level:2},{value:"Benefits to Database Developers: Drastically Lowering Development Costs and Simplifying the Creation of Purpose-Built Databases",id:"benefits-to-database-developers-drastically-lowering-development-costs-and-simplifying-the-creation-of-purpose-built-databases",level:2},{value:"The Future with GlueSQL",id:"the-future-with-gluesql",level:2},{value:"The Journey of the GlueSQL Team",id:"the-journey-of-the-gluesql-team",level:2},{value:"The Sustainability and Business Aspect of GlueSQL",id:"the-sustainability-and-business-aspect-of-gluesql",level:2},{value:"Conclusion",id:"conclusion",level:2}],d={toc:u},c="wrapper";function h(e){let{components:t,...a}=e;return(0,i.yg)(c,(0,n.A)({},d,a,{components:t,mdxType:"MDXLayout"}),(0,i.yg)("h2",{id:"introduction"},"Introduction"),(0,i.yg)("p",null,"GlueSQL is a versatile database project designed for exceptional portability across a broad range of environments, from embedded systems and servers to web and mobile platforms. The core goal is to support diverse storage environments and manage various data types with a standard SQL approach."),(0,i.yg)("p",null,"Imagine handling files like CSV, JSONL, and Parquet, or transforming key-value or NoSQL databases such as RocksDB, Redis, and MongoDB into SQL-supporting databases\u2014all feasible with GlueSQL. It can also operate with storages supported in web browsers."),(0,i.yg)("p",null,"GlueSQL's essential feature is providing a management layer for these diverse storage scenarios without requiring data migration. The broader aim is to facilitate portability of GlueSQL to any environment supporting read or read-write operations. This extends to APIs like GitHub, or messengers like Discord or Slack."),(0,i.yg)("p",null,"GlueSQL supports both structured and unstructured data and is written in Rust for compatibility with various environments. While portability is its core value, the emphasis is on creating an intuitive, comfortable development environment for easy custom storage implementation."),(0,i.yg)("p",null,"Ultimately, GlueSQL aims to significantly reduce the cost, time, and complexity of developing new databases. By leveraging GlueSQL for the parser, planner, and execution layer, developers can focus on creating specific storage implementations, leading to a more convenient query interface like SQL for many environments."),(0,i.yg)("h2",{id:"the-problem-why-reinvent-the-database"},"The Problem: Why Reinvent the Database?"),(0,i.yg)("p",null,"Despite the numerous database implementations that currently exist, the emergence of new databases continues. The primary reason behind this trend is our need for databases for a broad spectrum of distinct purposes. For instance, new databases are surfacing that are specifically optimized for Large Language Models (LLMs) like ChatGPT. The range is wide and diverse, encompassing embedded databases, OLAP for data analysis, OLTP databases optimized for online transactions, databases specialized for time-series data processing, and many more."),(0,i.yg)("p",null,"With such varied requirements, we find ourselves in constant need of fresh databases. However, constructing a database from scratch is a monumental task. It necessitates defining a query interface for handling the database and implementing a corresponding parser. Moreover, a separate execution layer for running operations must be built. Also, the planning layer, which is responsible for devising execution strategies, is a vital aspect of this process. Let's not forget about the critical storage layer that physically reads and stores the data. In a nutshell, there's a daunting amount of work involved in developing a new database."),(0,i.yg)("p",null,"Given these circumstances, it's understandable why numerous emerging databases resort to high pricing structures\u2014they need immediate revenue to offset continuous development costs."),(0,i.yg)("p",null,"But the story doesn't end here. Query interfaces like SQL are indeed useful for serious tasks, but they also provide excellent utility for handling simple log files such as CSV, JSONL, Parquet, and even for utilizing REST APIs for various applications. The issue arises when a complex query interface needs to be provided even for these lighter storage requirements\u2014it necessitates a development process almost identical to building a sophisticated database. Implementing an entire parser and execution layer just to add SQL support to an existing service can seem like an excessive burden."),(0,i.yg)("p",null,"Whether it's a simple storage environment or a serious task, the key lies in the storage layer, which involves the actual reading and storing of data. So, what if developers focused on implementing these storage mechanisms while the remaining parts could be handled using existing libraries? This is the role that GlueSQL aspires to play."),(0,i.yg)("h2",{id:"the-vision-of-gluesql"},"The Vision of GlueSQL"),(0,i.yg)("p",null,"The GlueSQL project aims to offer a unified query interface for various environments. The goal is to allow anyone to port and use SQL and GlueSQL's proprietary query builder, the AST Builder, in any desired environment. This could range from key-value databases, serious NoSQL databases, log files, and even REST API services. Essentially, if a service supports reading or read-writing data, regardless of the data type, it can readily support a complex query interface via GlueSQL."),(0,i.yg)("p",null,"Presently, the GlueSQL project itself directly supports a few storage types as reference storages. These include in-memory storage for non-persistent data handling, sled storage, which is a key-value database written in Rust, JSON storage for handling JSON and JSONL files, and a storage that ports SQL to the web browser's IndexedDB. While the GlueSQL Team is primarily developing these, the aim is to allow anyone to create such custom storages for a wide array of purposes, thus enabling them to assemble the database of their choosing."),(0,i.yg)("p",null,"Imagine using GlueSQL's SQL and AST Builder everywhere, with the simple method of swapping out storages to operate in diverse settings. It could significantly reduce software development costs. Developers wouldn't need to learn the different usage methods for each database. Instead, they could focus solely on implementing business logic using the same interface."),(0,i.yg)("p",null,"Our vision is to reduce database development costs by 10 times, or even more than 20 times. We aim to gather diverse database creators under the GlueSQL banner, making it the go-to solution for cost-effective database development."),(0,i.yg)("h2",{id:"benefits-to-database-users-unifying-query-interfaces-streamlining-software-development-and-reducing-costs"},"Benefits to Database Users: Unifying Query Interfaces, Streamlining Software Development, and Reducing Costs"),(0,i.yg)("p",null,"From the perspective of the users who engage with databases, there has always been the burden of learning different interfaces to interact with each database. The approach required to work with Redis is different from that necessary for MongoDB. Likewise, handling SQL databases necessitates using SQL. Although SQL databases generally use a common SQL, the SQL they support can considerably vary when examined in detail."),(0,i.yg)("p",null,"Naturally, there are legitimate reasons for such differences. Each database focuses on different areas, and to cater to specialized functionalities, they incorporate dedicated interface mechanisms. However, not all application development needs to utilize these database-specific core special functionalities."),(0,i.yg)("p",null,"Let's look at a couple of examples:"),(0,i.yg)("p",null,"Suppose you're developing a back-end application that uses MySQL as the database and Redis for caching. Due to the vast differences in handling SQL databases and Redis, you would have to develop using different methods when storing data."),(0,i.yg)("p",null,"Here's another scenario:\nImagine you're implementing a data migration pipeline between various databases and log files. Let's say you're transferring Parquet to Redis or MongoDB. In this case, you would need to convert data using different methods for each, all of which would be a cumbersome process."),(0,i.yg)("p",null,"In both of the above examples, GlueSQL can directly address and solve the issues. It offers the convenience of a uniform query interface to deal with these matters. In certain scenarios, even the construction of a data pipeline can potentially be solved with a single SQL query, thanks to GlueSQL."),(0,i.yg)("h2",{id:"benefits-to-database-developers-drastically-lowering-development-costs-and-simplifying-the-creation-of-purpose-built-databases"},"Benefits to Database Developers: Drastically Lowering Development Costs and Simplifying the Creation of Purpose-Built Databases"),(0,i.yg)("p",null,"If you want to support SQL in the desired environment, using GlueSQL essentially requires you to implement an interface for Storage. There's no need to support all functionalities from the beginning. You can start lightly, choosing and implementing storage features suitable for the environment you want to create. To facilitate this, GlueSQL also provides a library in the form of a test suite to easily validate the storage you've implemented."),(0,i.yg)("p",null,"Lowering development costs in this way will enable a broader range of developers to support the GlueSQL query interface. As more developers join, a significant synergy can be generated. Designing a query interface from scratch involves a great deal of work, including planning and supporting the interface for different target programming languages."),(0,i.yg)("p",null,"However, despite all this hard work, it is not easy to attract database users accustomed to different methods."),(0,i.yg)("p",null,"Consider that the SQL and AST Builder provided by GlueSQL are already securing numerous users. This eliminates the need for efforts to promote a newly planned query interface. Over the years, many new databases have emphasized compatibility with PostgreSQL or MySQL for similar reasons. As GlueSQL places a strong emphasis on portability in its query interface planning, it allows for more flexible configuration according to the desired situation. Through the AST Builder, it also eliminates the cost of porting to different languages."),(0,i.yg)("p",null,"For many database developers, using GlueSQL can be an optimal choice, as it can save costs and quickly secure users."),(0,i.yg)("p",null,"Let me mention one more thing: what's convenient for humans... could be applied to AI as well. Rather than making AI write automation code using different databases, providing a common query interface can be much more efficient."),(0,i.yg)("h2",{id:"the-future-with-gluesql"},"The Future with GlueSQL"),(0,i.yg)("p",null,"GlueSQL has been and will continue to improve and develop new features to enable portability in various environments. Thanks to the schemaless data support added last year, it is now possible to handle both structured data with schema and unstructured data like JSON simultaneously. This has significantly increased the range of storage environments that can be supported."),(0,i.yg)("p",null,"One of the key features added last year was the AST Builder. This feature allowed us to escape the confines of SQL and provide an interface for comfortably handling data in the programming languages used for development."),(0,i.yg)("p",null,"Of course, improving existing features is extremely important, and there are many new features to be added. As a major development plan this year, we aim to develop features to effectively attach GlueSQL to NoSQL databases with their own planners and execution layers. The GlueSQL query planner, currently at a basic level, will see significant changes this year. With the expansion of this planner, not only NoSQL databases but also other SQL databases could be supported without sacrificing performance using GlueSQL."),(0,i.yg)("p",null,"The synergy that arises from the combination of different databases is a significant bonus in this process."),(0,i.yg)("h2",{id:"the-journey-of-the-gluesql-team"},"The Journey of the GlueSQL Team"),(0,i.yg)("p",null,"The GlueSQL project was first conceived in the fall of 2019, and since then we have been developing it continuously. Personally, I have created various products in a variety of environments, including game development, backend server, and frontend development over the past decade. The experience gained through this process was a major motivation to start the GlueSQL project."),(0,i.yg)("p",null,"To put it grandly, the inconveniences felt while using different databases in various environments were a major motivation, wouldn't you say?"),(0,i.yg)("p",null,"The start was actually a bit simple. Around 2019, I was mainly doing web front-end development. However, the lack of a structured database for state management and internal data processing made it very uncomfortable, especially since I couldn't use SQL databases and the like. So I started to lightly create an SQL database that could run on a web browser. Also, I wanted to use Rust, but after failing to introduce it at the company I was working for at the time, I decided to use it in my own project."),(0,i.yg)("p",null,'But as I started developing, my dreams grew significantly. Beyond a SQL database that simply operates on a web browser, I started envisioning a database that fits the name "Glue", one that can easily be ported to various environments, and I continue that journey to this day.'),(0,i.yg)("p",null,"Whether I took the database project too lightly, or because the features I wanted kept increasing, the content to be developed kept expanding. As a result, I ended up investing full time in the GlueSQL project development for over three years. For a year in between, I even juggled full-time software engineering work alongside GlueSQL development. Currently, I'm back to developing the GlueSQL project full time, alongside various part-time contributors."),(0,i.yg)("p",null,"Now, we're getting very close to the starting point of the picture I wanted to create through GlueSQL, and thankfully, with contributors joining me, I am not alone."),(0,i.yg)("h2",{id:"the-sustainability-and-business-aspect-of-gluesql"},"The Sustainability and Business Aspect of GlueSQL"),(0,i.yg)("p",null,"I believe that what we create through GlueSQL will make a great contribution to the world and make many software engineers happy. This gives me immense strength to continue developing even in difficult situations. However, we cannot accomplish everything with pure passion alone. As much as the GlueSQL project can make a significant contribution, I also see it as holding great business value."),(0,i.yg)("p",null,"The business strategy of GlueSQL may be somewhat different from other databases. We distribute the project itself as open source under the Apache-2.0 license, so that anyone can use it fully, and we do not consider pricing methods such as restricting features to the storages we support. In fact, if there is any player who can do it better, there's no way to prevent them from taking the GlueSQL project and making it their own."),(0,i.yg)("p",null,"But we believe that GlueSQL has great potential in this regard. Anyone can participate and they are free to distribute their own storage in the way they want, whether it's open source, private, or commercial. This eliminates the need to create something to replace the GlueSQL project. We aim to prevent the need to recreate the wheel that we provide using GlueSQL."),(0,i.yg)("p",null,"Moreover, our GlueSQL team seeks to continually expand our group of developers and companies working with us. During this development process, while they can certainly implement everything on their own, there is also no reason not to collaborate with our GlueSQL Team, especially for databases like NoSQL that have their own planners and execution layers. If you have a REST API and want to enhance convenience through SQL support, you can do it yourself or you can collaborate with us."),(0,i.yg)("p",null,"In addition, for some storages, we can also participate as players in the same position as other custom storage developers. We plan to expand the GlueSQL ecosystem in various ways, such as technical support and storage development."),(0,i.yg)("p",null,"We are finally ready to provide GlueSQL to users at the production level. We are accelerating the development of GlueSQL. If you are a company interested in storage development like SQL support, or if you resonate with our vision and want to join us, please contact us at ",(0,i.yg)("a",{parentName:"p",href:"mailto:taehoon@gluesql.com"},"taehoon@gluesql.com"),"."),(0,i.yg)("h2",{id:"conclusion"},"Conclusion"),(0,i.yg)("p",null,"The continued emergence of new databases is driven by the demand for diverse and specialized databases, such as those optimized for Large Language Models (LLMs) and databases catering to unique requirements, like embedded databases, OLAP, OLTP, and time-series data processing. However, developing a new database from scratch is a significant undertaking, requiring extensive work, which often results in high costs."),(0,i.yg)("p",null,"GlueSQL presents a solution to this challenge by providing a unified query interface that can be ported across various environments, from key-value databases, NoSQL databases, log files, to REST APIs. It allows anyone to create custom storages, reducing the need for developers to build entirely new databases and to learn different usage methods for each database. Instead, they can focus on implementing their business logic using the same interface."),(0,i.yg)("p",null,"From a user perspective, GlueSQL offers the convenience of a unified query interface, easing the burden of learning different interfaces for each database. This simplification of interface use can also extend to AI, potentially enhancing the efficiency of AI automation."),(0,i.yg)("p",null,"GlueSQL's development plan includes significant enhancements to its query planner and aims to enable effective attachment of GlueSQL to NoSQL databases. The synergy of combining different databases is a valuable bonus in this process."),(0,i.yg)("p",null,"Since its inception in the fall of 2019, the GlueSQL team has continuously developed the project, driven by the desire to mitigate the inconveniences encountered while using different databases in various environments. The journey has been a rewarding one, with the GlueSQL project now at a point where it closely resembles the envisioned product."),(0,i.yg)("p",null,"GlueSQL, distributed under the Apache-2.0 license, is free for anyone to use and adapt. While the GlueSQL team welcomes collaboration with other developers and companies, they also see significant potential for the project as a business venture. The team is working to expand the GlueSQL ecosystem through a variety of initiatives, including technical support and storage development."),(0,i.yg)("p",null,"With GlueSQL now sufficiently prepared for practical applications, the team invites companies interested in storage development or those who share their vision to join them in their journey of revolutionizing database development."))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/77cc432a.d85baedd.js b/docs/0.16.0/assets/js/77cc432a.d85baedd.js new file mode 100644 index 00000000..53d63581 --- /dev/null +++ b/docs/0.16.0/assets/js/77cc432a.d85baedd.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[6867],{5680:(e,n,t)=>{t.d(n,{xA:()=>c,yg:()=>d});var r=t(6540);function a(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function l(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function o(e){for(var n=1;n=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var i=r.createContext({}),s=function(e){var n=r.useContext(i),t=n;return e&&(t="function"==typeof e?e(n):o(o({},n),e)),t},c=function(e){var n=s(e.components);return r.createElement(i.Provider,{value:n},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},y=r.forwardRef((function(e,n){var t=e.components,a=e.mdxType,l=e.originalType,i=e.parentName,c=p(e,["components","mdxType","originalType","parentName"]),u=s(t),y=a,d=u["".concat(i,".").concat(y)]||u[y]||m[y]||l;return t?r.createElement(d,o(o({ref:n},c),{},{components:t})):r.createElement(d,o({ref:n},c))}));function d(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var l=t.length,o=new Array(l);o[0]=y;var p={};for(var i in n)hasOwnProperty.call(n,i)&&(p[i]=n[i]);p.originalType=e,p[u]="string"==typeof e?e:a,o[1]=p;for(var s=2;s{t.r(n),t.d(n,{assets:()=>i,contentTitle:()=>o,default:()=>m,frontMatter:()=>l,metadata:()=>p,toc:()=>s});var r=t(8168),a=(t(6540),t(5680));const l={},o="PREPEND",p={unversionedId:"sql-syntax/functions/list-map/prepend",id:"sql-syntax/functions/list-map/prepend",title:"PREPEND",description:"The PREPEND function in SQL is used to prepend an element to a list.",source:"@site/docs/sql-syntax/functions/list-map/prepend.md",sourceDirName:"sql-syntax/functions/list-map",slug:"/sql-syntax/functions/list-map/prepend",permalink:"/docs/0.16.0/sql-syntax/functions/list-map/prepend",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"CONCAT",permalink:"/docs/0.16.0/sql-syntax/functions/list-map/concat"},next:{title:"SLICE",permalink:"/docs/0.16.0/sql-syntax/functions/list-map/slice"}},i={},s=[{value:"Syntax",id:"syntax",level:2},{value:"Examples",id:"examples",level:2}],c={toc:s},u="wrapper";function m(e){let{components:n,...t}=e;return(0,a.yg)(u,(0,r.A)({},c,t,{components:n,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"prepend"},"PREPEND"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"PREPEND")," function in SQL is used to prepend an element to a list."),(0,a.yg)("h2",{id:"syntax"},"Syntax"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"PREPEND(list, element)\n")),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"list"),": The list to which you want to prepend the element."),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"element"),": The element that you want to prepend to the list.")),(0,a.yg)("h2",{id:"examples"},"Examples"),(0,a.yg)("p",null,"First, create a table named ",(0,a.yg)("inlineCode",{parentName:"p"},"Prepend")," with columns for the list, an integer element, and a text element:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE Prepend (\n id INTEGER,\n items LIST,\n element INTEGER,\n element2 TEXT\n);\n")),(0,a.yg)("p",null,"Insert some data into the ",(0,a.yg)("inlineCode",{parentName:"p"},"Prepend")," table:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO Prepend VALUES\n(1, '[1, 2, 3]', 0, 'Foo');\n")),(0,a.yg)("p",null,"Use the ",(0,a.yg)("inlineCode",{parentName:"p"},"PREPEND")," function to prepend the integer element to the list:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT PREPEND(items, element) AS myprepend FROM Prepend;\n")),(0,a.yg)("p",null,"Use the ",(0,a.yg)("inlineCode",{parentName:"p"},"PREPEND")," function to prepend the text element to the list:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT PREPEND(items, element2) AS myprepend FROM Prepend;\n")),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"PREPEND")," function requires a list as the first parameter. If you try to use it with a non-list value, an error will occur:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT PREPEND(element, element2) AS myprepend FROM Prepend;\n")),(0,a.yg)("p",null,"You can also use the ",(0,a.yg)("inlineCode",{parentName:"p"},"PREPEND")," function when inserting data into a table. First, create a table named ",(0,a.yg)("inlineCode",{parentName:"p"},"Foo")," with a column for the list:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE Foo (\n elements LIST\n);\n")),(0,a.yg)("p",null,"Then, insert data into the ",(0,a.yg)("inlineCode",{parentName:"p"},"Foo")," table using the ",(0,a.yg)("inlineCode",{parentName:"p"},"PREPEND")," function:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO Foo VALUES (PREPEND(CAST('[1, 2, 3]' AS LIST), 0));\n")),(0,a.yg)("p",null,"Finally, retrieve the list from the ",(0,a.yg)("inlineCode",{parentName:"p"},"Foo")," table:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT elements AS myprepend FROM Foo;\n")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/7d170ab0.638674ff.js b/docs/0.16.0/assets/js/7d170ab0.638674ff.js new file mode 100644 index 00000000..1e923d4a --- /dev/null +++ b/docs/0.16.0/assets/js/7d170ab0.638674ff.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[969],{5680:(e,t,a)=>{a.d(t,{xA:()=>d,yg:()=>g});var n=a(6540);function s(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function r(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function i(e){for(var t=1;t=0||(s[a]=e[a]);return s}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(s[a]=e[a])}return s}var l=n.createContext({}),u=function(e){var t=n.useContext(l),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},d=function(e){var t=u(e.components);return n.createElement(l.Provider,{value:t},e.children)},c="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},h=n.forwardRef((function(e,t){var a=e.components,s=e.mdxType,r=e.originalType,l=e.parentName,d=o(e,["components","mdxType","originalType","parentName"]),c=u(a),h=s,g=c["".concat(l,".").concat(h)]||c[h]||p[h]||r;return a?n.createElement(g,i(i({ref:t},d),{},{components:a})):n.createElement(g,i({ref:t},d))}));function g(e,t){var a=arguments,s=t&&t.mdxType;if("string"==typeof e||s){var r=a.length,i=new Array(r);i[0]=h;var o={};for(var l in t)hasOwnProperty.call(t,l)&&(o[l]=t[l]);o.originalType=e,o[c]="string"==typeof e?e:s,i[1]=o;for(var u=2;u{a.r(t),a.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>p,frontMatter:()=>r,metadata:()=>o,toc:()=>u});var n=a(8168),s=(a(6540),a(5680));const r={title:"Breaking the Boundary between SQL and NoSQL Databases",description:"Breaking the Boundary between SQL and NoSQL Databases",slug:"breaking-the-boundary-between-sql-and-nosql",authors:[{name:"Taehoon Moon",title:"Creator of GlueSQL",url:"https://github.com/panarch",image_url:"https://github.com/panarch.png"}],tags:["sql","database","nosql"]},i="Breaking the Boundary between SQL and NoSQL Databases",o={permalink:"/docs/0.16.0/blog/breaking-the-boundary-between-sql-and-nosql",source:"@site/blog/2023-05-29-breaking-the-boundary.md",title:"Breaking the Boundary between SQL and NoSQL Databases",description:"Breaking the Boundary between SQL and NoSQL Databases",date:"2023-05-29T00:00:00.000Z",formattedDate:"May 29, 2023",tags:[{label:"sql",permalink:"/docs/0.16.0/blog/tags/sql"},{label:"database",permalink:"/docs/0.16.0/blog/tags/database"},{label:"nosql",permalink:"/docs/0.16.0/blog/tags/nosql"}],readingTime:10.055,hasTruncateMarker:!1,authors:[{name:"Taehoon Moon",title:"Creator of GlueSQL",url:"https://github.com/panarch",image_url:"https://github.com/panarch.png",imageURL:"https://github.com/panarch.png"}],frontMatter:{title:"Breaking the Boundary between SQL and NoSQL Databases",description:"Breaking the Boundary between SQL and NoSQL Databases",slug:"breaking-the-boundary-between-sql-and-nosql",authors:[{name:"Taehoon Moon",title:"Creator of GlueSQL",url:"https://github.com/panarch",image_url:"https://github.com/panarch.png",imageURL:"https://github.com/panarch.png"}],tags:["sql","database","nosql"]},prevItem:{title:"Test-Driven Documentation - Automating User Manual Creation in GlueSQL",permalink:"/docs/0.16.0/blog/test-driven-documentation"},nextItem:{title:"Release v0.14",permalink:"/docs/0.16.0/blog/release-v0.14"}},l={authorsImageUrls:[void 0]},u=[{value:"Introduction",id:"introduction",level:2},{value:"The Interface Perspective: SQL & AST Builder",id:"the-interface-perspective-sql--ast-builder",level:2},{value:"Structured & Unstructured Data",id:"structured--unstructured-data",level:2},{value:"Decomposing Database Functionality: Breaking Down SQL and NoSQL Features",id:"decomposing-database-functionality-breaking-down-sql-and-nosql-features",level:2},{value:"Conclusion",id:"conclusion",level:2}],d={toc:u},c="wrapper";function p(e){let{components:t,...a}=e;return(0,s.yg)(c,(0,n.A)({},d,a,{components:t,mdxType:"MDXLayout"}),(0,s.yg)("h2",{id:"introduction"},"Introduction"),(0,s.yg)("p",null,"The divide between SQL and NoSQL databases has often presented challenges in database management. GlueSQL, a unique database maker library, aims to blur this boundary, providing a versatile tool for handling these two distinct types of databases."),(0,s.yg)("p",null,"In this article, we explore how GlueSQL navigates the features of SQL and NoSQL databases, offering an integrated solution that promotes flexibility and efficiency. With its ability to unify disparate database types, GlueSQL heralds a new age of adaptable database creation and management."),(0,s.yg)("h2",{id:"the-interface-perspective-sql--ast-builder"},"The Interface Perspective: SQL & AST Builder"),(0,s.yg)("p",null,"When we talk about SQL databases, it's almost a given that they support SQL - the standard query language. Although there are slight variations between databases, the convenience of using a similar SQL language across multiple databases cannot be overstated. However, from a software engineer's perspective, there's room for improvement. In most software development scenarios, a specific programming language is used. SQL is a separate language, which can cause friction when integrating it into your software. As a result, rather than using raw SQL, many developers employ query builders or ORMs to manipulate SQL conveniently using their preferred programming language. Although it's not efficient to generate SQL using a query builder and then parse it again in the database, it's a practical and effective choice."),(0,s.yg)("p",null,"On the other hand, NoSQL databases offer different mechanisms. Some of them have their own language similar to SQL, but most provide an interface library developed specifically for each programming language. While SQL databases rely on external query builder libraries to provide an interface for each programming language, NoSQL databases mostly develop and offer these libraries themselves. If we discount the convenience of SQL language, this is one of the major factors that make NoSQL databases more comfortable to use. Since query builder libraries supporting SQL databases often cater to multiple SQL databases, they are limited in fully supporting unique features of each database. NoSQL databases, on the other hand, can freely manage their interface libraries without these restrictions."),(0,s.yg)("p",null,"Providing a query interface for each programming language is not a fundamental difference between SQL and NoSQL, but we generally accept it implicitly."),(0,s.yg)("p",null,"Let's see what happens if we break down this boundary, using GlueSQL as an example. As you can see from the SQL postfix, GlueSQL supports SQL and can be classified as an SQL database."),(0,s.yg)("pre",null,(0,s.yg)("code",{parentName:"pre",className:"language-sql"},'CREATE TABLE Glue (id INTEGER, name TEXT);\n\nINSERT INTO Glue VALUES (1, "hello"), (2, "gluesql");\n\nSELECT * FROM Glue WHERE id = 1;\n')),(0,s.yg)("p",null,"However, GlueSQL also supports its own query builder, like a NoSQL database.\n(Currently, only Rust is supported, but we're working on adding support for other languages.)"),(0,s.yg)("pre",null,(0,s.yg)("code",{parentName:"pre",className:"language-rust"},'table("Glue")\n .create_table()\n .add_column("id INTEGER")\n .add_column("name TEXT")\n .execute(glue)\n\ntable("Glue")\n .insert()\n .values(vec![\n vec![num(1), text("hello")],\n vec![num(2), text("gluesql")],\n ])\n .execute(glue)\n .await;\n\ntable("Glue")\n .select()\n .filter(col("id").eq(1))\n .execute(glue)\n .await;\n')),(0,s.yg)("p",null,"Let's reconsider the implicit distinction between SQL and NoSQL. GlueSQL indeed supports SQL, but it also officially develops and offers its own query builder. This query builder is not a secondary tool for SQL. While most SQL query builder libraries ultimately generate SQL strings, GlueSQL's builder directly creates an AST (Abstract Structure Tree) that is used for execution within GlueSQL. Hence, we call it the AST Builder. This means SQL and the AST Builder are two equally supported interfaces in GlueSQL."),(0,s.yg)("p",null,"This also offers an additional advantage:"),(0,s.yg)("pre",null,(0,s.yg)("code",{parentName:"pre",className:"language-rust"},'table("Glue")\n .select()\n // 1.\n .filter(col("id").eq(1))\n // 2.\n .filter("id = 1")\n .execute(glue)\n .await;\n')),(0,s.yg)("p",null,"Because GlueSQL already supports SQL, not only can you use the custom interface in the AST Builder, but you can also use familiar SQL syntax in part. Whether you use ",(0,s.yg)("inlineCode",{parentName:"p"},'col("id").eq(1)')," or ",(0,s.yg)("inlineCode",{parentName:"p"},'"id = 1"'),", you can use it in the way you prefer. The AST Builder interface, although initially unfamiliar, allows a gradual migration similar to writing SQL for your convenience."),(0,s.yg)("p",null,"Thus, we've dismantled one of the implicit distinctions between SQL and NoSQL. However, it's more of an implicit differentiation than a fundamental one. There are more significant design differences that we'll explore next."),(0,s.yg)("h2",{id:"structured--unstructured-data"},"Structured & Unstructured Data"),(0,s.yg)("p",null,"In this section, we'll discuss how SQL and NoSQL handle data. SQL generally deals with structured data, and recently, it's been made to support semi-structured data as well. On the other hand, NoSQL supports schemaless, unstructured data. Then, we'll explain in detail how GlueSQL handles these two types of data. The last part of this section will provide a segue into the next section where we'll discuss the decomposition of database functions."),(0,s.yg)("p",null,"When talking about SQL databases, one aspect is usually considered together: SQL databases have a defined schema."),(0,s.yg)("pre",null,(0,s.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE Foo (\n id INTEGER,\n name TEXT,\n rate FLOAT NULL\n);\n")),(0,s.yg)("p",null,"However, these days, SQL databases tend to support semi-structured data types, such as LIST or JSON. But, supporting completely schemaless, unstructured data is a different matter. SQL databases typically require a minimum schema."),(0,s.yg)("p",null,"What about NoSQL databases? As NoSQL databases vary significantly, we can't make definitive statements. But let's consider a typical document database like MongoDB. Unlike SQL databases, it doesn't enforce a schema. Essentially, you can insert any form of data directly. Often, NoSQL databases support schemaless data, but they lack features that enforce a schema like SQL. They generally support structure via validation methods, rather than structured access."),(0,s.yg)("p",null,"Is there no choice but to distinguish between structured data and unstructured, schemaless data so clearly? GlueSQL is being developed with the goal of being adaptable in various environments. Being forced to choose regarding this schema constraint was quite inconvenient. We started pondering if we couldn't benefit from both aspects - supporting both schema and schemaless data simultaneously, and we eventually found the answer. Let's look at how GlueSQL currently solves this issue through familiar SQL examples."),(0,s.yg)("pre",null,(0,s.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE Names (id INTEGER, name TEXT);\nINSERT INTO Names VALUES (1, 'glue'), (2, 'sql');\n")),(0,s.yg)("p",null,"You can create a regular table with a schema like this. But GlueSQL's choice for creating a schemaless table is as follows:"),(0,s.yg)("pre",null,(0,s.yg)("code",{parentName:"pre",className:"language-sql"},'CREATE TABLE Logs;\nINSERT INTO Logs VALUES\n (\'{ "id": 1, "value": 30 }\'),\n (\'{ "id": 2, "rate": 3.0, "list": [1, 2, 3] }\'),\n (\'{ "id": 3, "rate": 5.0, "value": 100 }\');\n')),(0,s.yg)("p",null,"It creates a table without column definitions! If you do this, GlueSQL recognizes the table as schemaless and processes it internally."),(0,s.yg)("pre",null,(0,s.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT id, rate, list[0] FROM Logs WHERE id = 2;\n")),(0,s.yg)("p",null,"Although the way to create the table was a bit special, using it isn't much different from the regular SQL SELECT statement. Not only can you differentiate between schema and schemaless when creating tables, but you can also use them interchangeably!"),(0,s.yg)("pre",null,(0,s.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT * FROM Names JOIN Logs ON Names.id = Logs.id;\n/*\n| id | list | name | rate | value |\n|----|---------|------|------|-------|\n| 1 | | glue | | 30 |\n| 2 |[1, 2, 3]| sql | 3 | |\n*/\n")),(0,s.yg)("p",null,"Here's an example of querying data by INNER JOINing the Names table, which has a schema, and the Logs table, which is schemaless. GlueSQL has resolved this problem by allowing the internal execution layer to handle both vector-type data, for cases where each row has a defined schema, and map-type data for schemaless cases."),(0,s.yg)("p",null,"Thanks to this, the variety of storage that can be supported through GlueSQL has expanded significantly. If there were previously limitations to supporting NoSQL databases that support schemaless data, that is no longer the case. The reference storage where you can directly experience this schemaless data support is JSON Storage. It offers features that allow you to deal directly with unstructured data like JSON using GlueSQL."),(0,s.yg)("p",null,"If GlueSQL starts from the perspective of an SQL database and expands, by providing the AST Builder directly, it once blurs the boundary, and by supporting unstructured data simultaneously, it knocks down the boundary once more. How do you like it?"),(0,s.yg)("h2",{id:"decomposing-database-functionality-breaking-down-sql-and-nosql-features"},"Decomposing Database Functionality: Breaking Down SQL and NoSQL Features"),(0,s.yg)("p",null,"The distinction between SQL and NoSQL is not just about whether they support unstructured data. Of course, there are examples like unstructured data, which is mainly supported only in NoSQL, but in many cases, SQL databases tend to support more diverse and complex queries. NoSQL often gains other advantages in exchange for reducing the range of query support provided by SQL databases."),(0,s.yg)("p",null,'GlueSQL is ambitious. It has devised a rather interesting method to support all of this through SQL and the AST Builder, with the same interface. When we usually say SQL database, it implicitly assumes that a lot of features have been fully implemented. Create tables by specifying a schema, modify schemas with "alter table", support both clustered and non-clustered indexes, and support transactions. And there\'s so much more. But the functionality that is naturally supported in SQL databases may not be natural in other environments.'),(0,s.yg)("p",null,"Let's think about JSON Storage. GlueSQL's JSON Storage allows you to handle JSON, JSONL files using SQL and the AST Builder. This JSON Storage does not support atomic operations or transactions. Of course, it would be great if it did, but implementing and executing them would be a significant performance burden. In most cases, when you want to simply browse and handle JSONL files, the overhead caused by transactions can be an unnecessary burden. In this case, you want to handle JSON, JSONL files using SQL, but you don't necessarily need transactions."),(0,s.yg)("p",null,"To meet the requirements of these diverse environments, GlueSQL has separated the functionality of what we usually call an SQL database into multiple independent interfaces.\n",(0,s.yg)("inlineCode",{parentName:"p"},"Store"),", ",(0,s.yg)("inlineCode",{parentName:"p"},"StoreMut"),", ",(0,s.yg)("inlineCode",{parentName:"p"},"AlterTable"),", ",(0,s.yg)("inlineCode",{parentName:"p"},"Transaction"),", ..\nThese are just a few of the various storage interfaces that GlueSQL currently supports.\nThe way it works can be summarized like this:\nIf you implement ",(0,s.yg)("inlineCode",{parentName:"p"},"Store"),", you can use ",(0,s.yg)("inlineCode",{parentName:"p"},"SELECT"),".\nAnd if you implement both ",(0,s.yg)("inlineCode",{parentName:"p"},"Store")," and ",(0,s.yg)("inlineCode",{parentName:"p"},"StoreMut"),", you can support quite a number of basic SQL statements including ",(0,s.yg)("inlineCode",{parentName:"p"},"SELECT"),".\nYou can manage tables with ",(0,s.yg)("inlineCode",{parentName:"p"},"CREATE TABLE"),", ",(0,s.yg)("inlineCode",{parentName:"p"},"DROP TABLE"),", and handle data using ",(0,s.yg)("inlineCode",{parentName:"p"},"INSERT"),", ",(0,s.yg)("inlineCode",{parentName:"p"},"UPDATE"),", ",(0,s.yg)("inlineCode",{parentName:"p"},"DELETE")," statements.\nIf you only need to retrieve data, you only need to implement ",(0,s.yg)("inlineCode",{parentName:"p"},"Store"),".\nIf you want to support the ",(0,s.yg)("inlineCode",{parentName:"p"},"ALTER TABLE")," statement, you can additionally implement the ",(0,s.yg)("inlineCode",{parentName:"p"},"AlterTable")," interface.\nThe Transaction interface works the same way.\nThe interesting part is that, except for Store and StoreMut, all other storage interfaces can be implemented independently. GlueSQL allows you to choose and implement only the features you need.\nAnd it's not just about providing interfaces. It also provides integration tests suitable for each situation to verify what you have implemented. You just need to implement the interface and import the corresponding test case for verification."),(0,s.yg)("p",null,"In addition to supporting both structured and unstructured data simultaneously, GlueSQL provides the ability to divide the functionality of a database into multiple independent features and selectively implement them. This allows GlueSQL to be ported to a wide variety of environments without any burden."),(0,s.yg)("h2",{id:"conclusion"},"Conclusion"),(0,s.yg)("p",null,"GlueSQL, while serving as a database that provides its own reference storage, is fundamentally a library designed to simplify the creation of databases. One of the substantial challenges GlueSQL had to overcome in order to support a diverse array of environments was to address the distinctive features that separate conventional SQL databases from NoSQL databases. GlueSQL achieved this through several innovative approaches, managing to support both categories simultaneously despite their significantly different characteristics."),(0,s.yg)("p",null,"It offers support for SQL alongside an AST Builder, and accommodates both structured and unstructured data. Additionally, it decomposes database functionalities into multiple independent features, allowing each environment to selectively implement the functionalities it requires."),(0,s.yg)("p",null,"These unique attributes enable GlueSQL to live up to its 'Glue' prefix by facilitating effortless porting across various environments. While we have been developing it for several years, there is still much ground to cover. However, the fact that we are now able to introduce it publicly attests to our successful technological validation and completion of a demonstrable level of implementation."),(0,s.yg)("p",null,"Through GlueSQL, we hope to provide developers with a unified query interface that can be customized according to their needs, thereby enabling them to produce efficient products more effortlessly. There's a promising future ahead for GlueSQL, and we look forward to its contributions to the technology community."))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/7e0ce508.7eebaf2e.js b/docs/0.16.0/assets/js/7e0ce508.7eebaf2e.js new file mode 100644 index 00000000..eea45f88 --- /dev/null +++ b/docs/0.16.0/assets/js/7e0ce508.7eebaf2e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[7722],{5680:(e,n,t)=>{t.d(n,{xA:()=>g,yg:()=>d});var r=t(6540);function a(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function o(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function l(e){for(var n=1;n=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var u=r.createContext({}),s=function(e){var n=r.useContext(u),t=n;return e&&(t="function"==typeof e?e(n):l(l({},n),e)),t},g=function(e){var n=s(e.components);return r.createElement(u.Provider,{value:n},e.children)},p="mdxType",c={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},m=r.forwardRef((function(e,n){var t=e.components,a=e.mdxType,o=e.originalType,u=e.parentName,g=i(e,["components","mdxType","originalType","parentName"]),p=s(t),m=a,d=p["".concat(u,".").concat(m)]||p[m]||c[m]||o;return t?r.createElement(d,l(l({ref:n},g),{},{components:t})):r.createElement(d,l({ref:n},g))}));function d(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var o=t.length,l=new Array(o);l[0]=m;var i={};for(var u in n)hasOwnProperty.call(n,u)&&(i[u]=n[u]);i.originalType=e,i[p]="string"==typeof e?e:a,l[1]=i;for(var s=2;s{t.r(n),t.d(n,{assets:()=>u,contentTitle:()=>l,default:()=>c,frontMatter:()=>o,metadata:()=>i,toc:()=>s});var r=t(8168),a=(t(6540),t(5680));const o={},l="ROUND",i={unversionedId:"sql-syntax/functions/math/round",id:"sql-syntax/functions/math/round",title:"ROUND",description:"The ROUND function is used to round a number to the nearest integer value. It takes a single floating-point or integer value as its argument and returns a floating-point value.",source:"@site/docs/sql-syntax/functions/math/round.md",sourceDirName:"sql-syntax/functions/math",slug:"/sql-syntax/functions/math/round",permalink:"/docs/0.16.0/sql-syntax/functions/math/round",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"RAND",permalink:"/docs/0.16.0/sql-syntax/functions/math/rand"},next:{title:"SIGN",permalink:"/docs/0.16.0/sql-syntax/functions/math/sign"}},u={},s=[{value:"Syntax",id:"syntax",level:2},{value:"Examples",id:"examples",level:2},{value:"Example 1: Using ROUND function",id:"example-1-using-round-function",level:3},{value:"Errors",id:"errors",level:2},{value:"Example 2: Using ROUND with a string argument",id:"example-2-using-round-with-a-string-argument",level:3},{value:"Example 3: Using ROUND with a boolean argument",id:"example-3-using-round-with-a-boolean-argument",level:3}],g={toc:s},p="wrapper";function c(e){let{components:n,...t}=e;return(0,a.yg)(p,(0,r.A)({},g,t,{components:n,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"round"},"ROUND"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"ROUND")," function is used to round a number to the nearest integer value. It takes a single floating-point or integer value as its argument and returns a floating-point value."),(0,a.yg)("h2",{id:"syntax"},"Syntax"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"ROUND(value)\n")),(0,a.yg)("h2",{id:"examples"},"Examples"),(0,a.yg)("p",null,"Let's consider a table named ",(0,a.yg)("inlineCode",{parentName:"p"},"SingleItem")," with the following schema:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE SingleItem (id INTEGER);\n")),(0,a.yg)("p",null,"Insert a row into the ",(0,a.yg)("inlineCode",{parentName:"p"},"SingleItem")," table:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO SingleItem VALUES (0);\n")),(0,a.yg)("h3",{id:"example-1-using-round-function"},"Example 1: Using ROUND function"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT ROUND(0.3) AS round1,\nROUND(-0.8) AS round2,\nROUND(10) AS round3,\nROUND(6.87421) AS round4\nFROM SingleItem;\n")),(0,a.yg)("p",null,"Result:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre"},"round1 | round2 | round3 | round4\n-------+--------+--------+--------\n 0.0 | -1.0 | 10.0 | 7.0\n")),(0,a.yg)("p",null,"Note that the returned values are floating-point numbers, even though they represent integer values."),(0,a.yg)("h2",{id:"errors"},"Errors"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"ROUND")," function expects a floating-point or integer value as its argument. Providing any other type, such as a string or boolean, will result in an error."),(0,a.yg)("h3",{id:"example-2-using-round-with-a-string-argument"},"Example 2: Using ROUND with a string argument"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT ROUND('string') AS round FROM SingleItem;\n")),(0,a.yg)("p",null,"Error: Function requires a floating-point or integer value."),(0,a.yg)("h3",{id:"example-3-using-round-with-a-boolean-argument"},"Example 3: Using ROUND with a boolean argument"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT ROUND(TRUE) AS round FROM SingleItem;\n")),(0,a.yg)("p",null,"Error: Function requires a floating-point or integer value."))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/7ea7f008.1e86f06b.js b/docs/0.16.0/assets/js/7ea7f008.1e86f06b.js new file mode 100644 index 00000000..50c9773c --- /dev/null +++ b/docs/0.16.0/assets/js/7ea7f008.1e86f06b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[4217],{5680:(e,t,r)=>{r.d(t,{xA:()=>l,yg:()=>f});var n=r(6540);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var d=n.createContext({}),u=function(e){var t=n.useContext(d),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},l=function(e){var t=u(e.components);return n.createElement(d.Provider,{value:t},e.children)},s="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,d=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),s=u(r),m=a,f=s["".concat(d,".").concat(m)]||s[m]||p[m]||o;return r?n.createElement(f,i(i({ref:t},l),{},{components:r})):n.createElement(f,i({ref:t},l))}));function f(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,i=new Array(o);i[0]=m;var c={};for(var d in t)hasOwnProperty.call(t,d)&&(c[d]=t[d]);c.originalType=e,c[s]="string"==typeof e?e:a,i[1]=c;for(var u=2;u{r.r(t),r.d(t,{assets:()=>d,contentTitle:()=>i,default:()=>p,frontMatter:()=>o,metadata:()=>c,toc:()=>u});var n=r(8168),a=(r(6540),r(5680));const o={},i="Date and Time Extraction",c={unversionedId:"ast-builder/functions/date-&-time/date-and-time-extraction",id:"ast-builder/functions/date-&-time/date-and-time-extraction",title:"Date and Time Extraction",description:"Todo",source:"@site/docs/ast-builder/functions/date-&-time/date-and-time-extraction.md",sourceDirName:"ast-builder/functions/date-&-time",slug:"/ast-builder/functions/date-&-time/date-and-time-extraction",permalink:"/docs/0.16.0/ast-builder/functions/date-&-time/date-and-time-extraction",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"Current Date and Time",permalink:"/docs/0.16.0/ast-builder/functions/date-&-time/current-date-and-time"},next:{title:"Formatting",permalink:"/docs/0.16.0/ast-builder/functions/date-&-time/formatting"}},d={},u=[{value:"Todo",id:"todo",level:2}],l={toc:u},s="wrapper";function p(e){let{components:t,...r}=e;return(0,a.yg)(s,(0,n.A)({},l,r,{components:t,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"date-and-time-extraction"},"Date and Time Extraction"),(0,a.yg)("h2",{id:"todo"},"Todo"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre"},"- EXTRACT: Extracts a part of a date or time (like day, month, year, hour, minute, etc.).\n")))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/7f479c52.1ff8ee6e.js b/docs/0.16.0/assets/js/7f479c52.1ff8ee6e.js new file mode 100644 index 00000000..b01a65be --- /dev/null +++ b/docs/0.16.0/assets/js/7f479c52.1ff8ee6e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[9070],{8:o=>{o.exports=JSON.parse('{"permalink":"/docs/0.16.0/blog/tags/automation","page":1,"postsPerPage":10,"totalPages":1,"totalCount":1,"blogDescription":"Blog","blogTitle":"Blog"}')}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/814f3328.24525a8b.js b/docs/0.16.0/assets/js/814f3328.24525a8b.js new file mode 100644 index 00000000..5ff18e07 --- /dev/null +++ b/docs/0.16.0/assets/js/814f3328.24525a8b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[7472],{5513:e=>{e.exports=JSON.parse('{"title":"Recent posts","items":[{"title":"Release v0.15","permalink":"/docs/0.16.0/blog/release-v0.15"},{"title":"GlueSQL - Revolutionizing Databases by Unifying Query Interfaces","permalink":"/docs/0.16.0/blog/revolutionizing-databases-by-unifying-query-interfaces"},{"title":"Test-Driven Documentation - Automating User Manual Creation in GlueSQL","permalink":"/docs/0.16.0/blog/test-driven-documentation"},{"title":"Breaking the Boundary between SQL and NoSQL Databases","permalink":"/docs/0.16.0/blog/breaking-the-boundary-between-sql-and-nosql"},{"title":"Release v0.14","permalink":"/docs/0.16.0/blog/release-v0.14"}]}')}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/81bf07f5.ce836a1d.js b/docs/0.16.0/assets/js/81bf07f5.ce836a1d.js new file mode 100644 index 00000000..37c8041f --- /dev/null +++ b/docs/0.16.0/assets/js/81bf07f5.ce836a1d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[1978],{5680:(e,t,n)=>{n.d(t,{xA:()=>p,yg:()=>f});var r=n(6540);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=r.createContext({}),l=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=l(e.components);return r.createElement(s.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,s=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),u=l(n),m=o,f=u["".concat(s,".").concat(m)]||u[m]||d[m]||a;return n?r.createElement(f,i(i({ref:t},p),{},{components:n})):r.createElement(f,i({ref:t},p))}));function f(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,i=new Array(a);i[0]=m;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c[u]="string"==typeof e?e:o,i[1]=c;for(var l=2;l{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>d,frontMatter:()=>a,metadata:()=>c,toc:()=>l});var r=n(8168),o=(n(6540),n(5680));const a={},i="List and Map Concatenation",c={unversionedId:"ast-builder/functions/list-&-map/list-and-map-concatenation",id:"ast-builder/functions/list-&-map/list-and-map-concatenation",title:"List and Map Concatenation",description:"Todo",source:"@site/docs/ast-builder/functions/list-&-map/list-and-map-concatenation.md",sourceDirName:"ast-builder/functions/list-&-map",slug:"/ast-builder/functions/list-&-map/list-and-map-concatenation",permalink:"/docs/0.16.0/ast-builder/functions/list-&-map/list-and-map-concatenation",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"Formatting",permalink:"/docs/0.16.0/ast-builder/functions/date-&-time/formatting"},next:{title:"List Manipulation",permalink:"/docs/0.16.0/ast-builder/functions/list-&-map/list-manipulation"}},s={},l=[{value:"Todo",id:"todo",level:2}],p={toc:l},u="wrapper";function d(e){let{components:t,...n}=e;return(0,o.yg)(u,(0,r.A)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,o.yg)("h1",{id:"list-and-map-concatenation"},"List and Map Concatenation"),(0,o.yg)("h2",{id:"todo"},"Todo"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre"},"- CONCAT: Combines two or more lists or maps into one.\n")))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/81f6aa2c.ee049a89.js b/docs/0.16.0/assets/js/81f6aa2c.ee049a89.js new file mode 100644 index 00000000..c9fa3f49 --- /dev/null +++ b/docs/0.16.0/assets/js/81f6aa2c.ee049a89.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[9033],{5680:(e,t,n)=>{n.d(t,{xA:()=>u,yg:()=>d});var r=n(6540);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var c=r.createContext({}),s=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},u=function(e){var t=s(e.components);return r.createElement(c.Provider,{value:t},e.children)},p="mdxType",y={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},g=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,l=e.originalType,c=e.parentName,u=o(e,["components","mdxType","originalType","parentName"]),p=s(n),g=a,d=p["".concat(c,".").concat(g)]||p[g]||y[g]||l;return n?r.createElement(d,i(i({ref:t},u),{},{components:n})):r.createElement(d,i({ref:t},u))}));function d(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var l=n.length,i=new Array(l);i[0]=g;var o={};for(var c in t)hasOwnProperty.call(t,c)&&(o[c]=t[c]);o.originalType=e,o[p]="string"==typeof e?e:a,i[1]=o;for(var s=2;s{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>y,frontMatter:()=>l,metadata:()=>o,toc:()=>s});var r=n(8168),a=(n(6540),n(5680));const l={},i="LOWER",o={unversionedId:"sql-syntax/functions/text/lower",id:"sql-syntax/functions/text/lower",title:"LOWER",description:"The LOWER function in SQL returns a string in which all alphabetic characters in a specified string are converted to lowercase.",source:"@site/docs/sql-syntax/functions/text/lower.md",sourceDirName:"sql-syntax/functions/text",slug:"/sql-syntax/functions/text/lower",permalink:"/docs/0.16.0/sql-syntax/functions/text/lower",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"LEFT",permalink:"/docs/0.16.0/sql-syntax/functions/text/left"},next:{title:"LPAD",permalink:"/docs/0.16.0/sql-syntax/functions/text/lpad"}},c={},s=[{value:"Syntax",id:"syntax",level:2},{value:"Parameters",id:"parameters",level:2},{value:"Return Value",id:"return-value",level:2},{value:"Errors",id:"errors",level:2},{value:"Examples",id:"examples",level:2}],u={toc:s},p="wrapper";function y(e){let{components:t,...n}=e;return(0,a.yg)(p,(0,r.A)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"lower"},"LOWER"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"LOWER")," function in SQL returns a string in which all alphabetic characters in a specified string are converted to lowercase."),(0,a.yg)("h2",{id:"syntax"},"Syntax"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"LOWER(string)\n")),(0,a.yg)("h2",{id:"parameters"},"Parameters"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"string"),": The original string to convert.")),(0,a.yg)("h2",{id:"return-value"},"Return Value"),(0,a.yg)("p",null,"The function returns a new string that is the same as the original string, but with all uppercase characters converted to lowercase. Non-alphabetic characters in the string are unaffected."),(0,a.yg)("h2",{id:"errors"},"Errors"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},"If the ",(0,a.yg)("inlineCode",{parentName:"li"},"string")," argument is not a string, a ",(0,a.yg)("inlineCode",{parentName:"li"},"FunctionRequiresStringValue")," error will be returned.")),(0,a.yg)("h2",{id:"examples"},"Examples"),(0,a.yg)("p",null,"Consider a table ",(0,a.yg)("inlineCode",{parentName:"p"},"Item")," created and filled with the following data:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE Item (\n name TEXT\n);\nINSERT INTO Item VALUES ('ABCD'), ('Abcd'), ('abcd');\n")),(0,a.yg)("p",null,"You can use the ",(0,a.yg)("inlineCode",{parentName:"p"},"LOWER")," function to convert all ",(0,a.yg)("inlineCode",{parentName:"p"},"name")," values to lowercase:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT LOWER(name) AS lower_name FROM Item;\n")),(0,a.yg)("p",null,"This will return:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre"},"abcd\nabcd\nabcd\n")),(0,a.yg)("p",null,"Note that the ",(0,a.yg)("inlineCode",{parentName:"p"},"LOWER")," function affects only alphabetic characters. Non-alphabetic characters in the string remain unchanged."))}y.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/8382.3c17fd52.js b/docs/0.16.0/assets/js/8382.3c17fd52.js new file mode 100644 index 00000000..3489d6ca --- /dev/null +++ b/docs/0.16.0/assets/js/8382.3c17fd52.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[8382],{6669:(e,t,a)=>{a.d(t,{A:()=>h});var l=a(6540),r=a(53),n=a(9408),o=a(4581),s=a(5489),i=a(1312);const m={sidebar:"sidebar_re4s",sidebarItemTitle:"sidebarItemTitle_pO2u",sidebarItemList:"sidebarItemList_Yudw",sidebarItem:"sidebarItem__DBe",sidebarItemLink:"sidebarItemLink_mo7H",sidebarItemLinkActive:"sidebarItemLinkActive_I1ZP"};function c(e){let{sidebar:t}=e;return l.createElement("aside",{className:"col col--3"},l.createElement("nav",{className:(0,r.A)(m.sidebar,"thin-scrollbar"),"aria-label":(0,i.T)({id:"theme.blog.sidebar.navAriaLabel",message:"Blog recent posts navigation",description:"The ARIA label for recent posts in the blog sidebar"})},l.createElement("div",{className:(0,r.A)(m.sidebarItemTitle,"margin-bottom--md")},t.title),l.createElement("ul",{className:(0,r.A)(m.sidebarItemList,"clean-list")},t.items.map((e=>l.createElement("li",{key:e.permalink,className:m.sidebarItem},l.createElement(s.A,{isNavLink:!0,to:e.permalink,className:m.sidebarItemLink,activeClassName:m.sidebarItemLinkActive},e.title)))))))}var u=a(5600);function d(e){let{sidebar:t}=e;return l.createElement("ul",{className:"menu__list"},t.items.map((e=>l.createElement("li",{key:e.permalink,className:"menu__list-item"},l.createElement(s.A,{isNavLink:!0,to:e.permalink,className:"menu__link",activeClassName:"menu__link--active"},e.title)))))}function g(e){return l.createElement(u.GX,{component:d,props:e})}function p(e){let{sidebar:t}=e;const a=(0,o.l)();return t?.items.length?"mobile"===a?l.createElement(g,{sidebar:t}):l.createElement(c,{sidebar:t}):null}function h(e){const{sidebar:t,toc:a,children:o,...s}=e,i=t&&t.items.length>0;return l.createElement(n.A,s,l.createElement("div",{className:"container margin-vert--lg"},l.createElement("div",{className:"row"},l.createElement(p,{sidebar:t}),l.createElement("main",{className:(0,r.A)("col",{"col--7":i,"col--9 col--offset-1":!i}),itemScope:!0,itemType:"http://schema.org/Blog"},o),a&&l.createElement("div",{className:"col col--2"},a))))}},8258:(e,t,a)=>{a.d(t,{A:()=>M});var l=a(6540),r=a(53),n=a(7131),o=a(6025);function s(e){let{children:t,className:a}=e;const{frontMatter:r,assets:s,metadata:{description:i}}=(0,n.e)(),{withBaseUrl:m}=(0,o.h)(),c=s.image??r.image,u=r.keywords??[];return l.createElement("article",{className:a,itemProp:"blogPost",itemScope:!0,itemType:"http://schema.org/BlogPosting"},i&&l.createElement("meta",{itemProp:"description",content:i}),c&&l.createElement("link",{itemProp:"image",href:m(c,{absolute:!0})}),u.length>0&&l.createElement("meta",{itemProp:"keywords",content:u.join(",")}),t)}var i=a(5489);const m={title:"title_f1Hy"};function c(e){let{className:t}=e;const{metadata:a,isBlogPostPage:o}=(0,n.e)(),{permalink:s,title:c}=a,u=o?"h1":"h2";return l.createElement(u,{className:(0,r.A)(m.title,t),itemProp:"headline"},o?c:l.createElement(i.A,{itemProp:"url",to:s},c))}var u=a(1312),d=a(8227);const g={container:"container_mt6G"};function p(e){let{readingTime:t}=e;const a=function(){const{selectMessage:e}=(0,d.W)();return t=>{const a=Math.ceil(t);return e(a,(0,u.T)({id:"theme.blog.post.readingTime.plurals",description:'Pluralized label for "{readingTime} min read". Use as much plural forms (separated by "|") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)',message:"One min read|{readingTime} min read"},{readingTime:a}))}}();return l.createElement(l.Fragment,null,a(t))}function h(e){let{date:t,formattedDate:a}=e;return l.createElement("time",{dateTime:t,itemProp:"datePublished"},a)}function E(){return l.createElement(l.Fragment,null," \xb7 ")}function b(e){let{className:t}=e;const{metadata:a}=(0,n.e)(),{date:o,formattedDate:s,readingTime:i}=a;return l.createElement("div",{className:(0,r.A)(g.container,"margin-vert--md",t)},l.createElement(h,{date:o,formattedDate:s}),void 0!==i&&l.createElement(l.Fragment,null,l.createElement(E,null),l.createElement(p,{readingTime:i})))}function f(e){return e.href?l.createElement(i.A,e):l.createElement(l.Fragment,null,e.children)}function v(e){let{author:t,className:a}=e;const{name:n,title:o,url:s,imageURL:i,email:m}=t,c=s||m&&`mailto:${m}`||void 0;return l.createElement("div",{className:(0,r.A)("avatar margin-bottom--sm",a)},i&&l.createElement(f,{href:c,className:"avatar__photo-link"},l.createElement("img",{className:"avatar__photo",src:i,alt:n,itemProp:"image"})),n&&l.createElement("div",{className:"avatar__intro",itemProp:"author",itemScope:!0,itemType:"https://schema.org/Person"},l.createElement("div",{className:"avatar__name"},l.createElement(f,{href:c,itemProp:"url"},l.createElement("span",{itemProp:"name"},n))),o&&l.createElement("small",{className:"avatar__subtitle",itemProp:"description"},o)))}const P={authorCol:"authorCol_Hf19",imageOnlyAuthorRow:"imageOnlyAuthorRow_pa_O",imageOnlyAuthorCol:"imageOnlyAuthorCol_G86a"};function A(e){let{className:t}=e;const{metadata:{authors:a},assets:o}=(0,n.e)();if(0===a.length)return null;const s=a.every((e=>{let{name:t}=e;return!t}));return l.createElement("div",{className:(0,r.A)("margin-top--md margin-bottom--sm",s?P.imageOnlyAuthorRow:"row",t)},a.map(((e,t)=>l.createElement("div",{className:(0,r.A)(!s&&"col col--6",s?P.imageOnlyAuthorCol:P.authorCol),key:t},l.createElement(v,{author:{...e,imageURL:o.authorsImageUrls[t]??e.imageURL}})))))}function N(){return l.createElement("header",null,l.createElement(c,null),l.createElement(b,null),l.createElement(A,null))}var _=a(440),k=a(7780);function T(e){let{children:t,className:a}=e;const{isBlogPostPage:o}=(0,n.e)();return l.createElement("div",{id:o?_.blogPostContainerID:void 0,className:(0,r.A)("markdown",a),itemProp:"articleBody"},l.createElement(k.A,null,t))}var w=a(1943),I=a(2053),y=a(8168);function F(){return l.createElement("b",null,l.createElement(u.A,{id:"theme.blog.post.readMore",description:"The label used in blog post item excerpts to link to full blog posts"},"Read More"))}function L(e){const{blogPostTitle:t,...a}=e;return l.createElement(i.A,(0,y.A)({"aria-label":(0,u.T)({message:"Read more about {title}",id:"theme.blog.post.readMoreLabel",description:"The ARIA label for the link to full blog posts from excerpts"},{title:t})},a),l.createElement(F,null))}const B={blogPostFooterDetailsFull:"blogPostFooterDetailsFull_mRVl"};function C(){const{metadata:e,isBlogPostPage:t}=(0,n.e)(),{tags:a,title:o,editUrl:s,hasTruncateMarker:i}=e,m=!t&&i,c=a.length>0;return c||m||s?l.createElement("footer",{className:(0,r.A)("row docusaurus-mt-lg",t&&B.blogPostFooterDetailsFull)},c&&l.createElement("div",{className:(0,r.A)("col",{"col--9":m})},l.createElement(I.A,{tags:a})),t&&s&&l.createElement("div",{className:"col margin-top--sm"},l.createElement(w.A,{editUrl:s})),m&&l.createElement("div",{className:(0,r.A)("col text--right",{"col--3":c})},l.createElement(L,{blogPostTitle:o,to:e.permalink}))):null}function M(e){let{children:t,className:a}=e;const o=function(){const{isBlogPostPage:e}=(0,n.e)();return e?void 0:"margin-bottom--xl"}();return l.createElement(s,{className:(0,r.A)(o,a)},l.createElement(N,null),l.createElement(T,null,t),l.createElement(C,null))}},7131:(e,t,a)=>{a.d(t,{e:()=>s,i:()=>o});var l=a(6540),r=a(9532);const n=l.createContext(null);function o(e){let{children:t,content:a,isBlogPostPage:r=!1}=e;const o=function(e){let{content:t,isBlogPostPage:a}=e;return(0,l.useMemo)((()=>({metadata:t.metadata,frontMatter:t.frontMatter,assets:t.assets,toc:t.toc,isBlogPostPage:a})),[t,a])}({content:a,isBlogPostPage:r});return l.createElement(n.Provider,{value:o},t)}function s(){const e=(0,l.useContext)(n);if(null===e)throw new r.dV("BlogPostProvider");return e}},8227:(e,t,a)=>{a.d(t,{W:()=>m});var l=a(6540),r=a(4586);const n=["zero","one","two","few","many","other"];function o(e){return n.filter((t=>e.includes(t)))}const s={locale:"en",pluralForms:o(["one","other"]),select:e=>1===e?"one":"other"};function i(){const{i18n:{currentLocale:e}}=(0,r.A)();return(0,l.useMemo)((()=>{try{return function(e){const t=new Intl.PluralRules(e);return{locale:e,pluralForms:o(t.resolvedOptions().pluralCategories),select:e=>t.select(e)}}(e)}catch(t){return console.error(`Failed to use Intl.PluralRules for locale "${e}".\nDocusaurus will fallback to the default (English) implementation.\nError: ${t.message}\n`),s}}),[e])}function m(){const e=i();return{selectMessage:(t,a)=>function(e,t,a){const l=e.split("|");if(1===l.length)return l[0];l.length>a.pluralForms.length&&console.error(`For locale=${a.locale}, a maximum of ${a.pluralForms.length} plural forms are expected (${a.pluralForms.join(",")}), but the message contains ${l.length}: ${e}`);const r=a.select(t),n=a.pluralForms.indexOf(r);return l[Math.min(n,l.length-1)]}(a,t,e)}}}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/83b912d4.ab8880e8.js b/docs/0.16.0/assets/js/83b912d4.ab8880e8.js new file mode 100644 index 00000000..400c66ee --- /dev/null +++ b/docs/0.16.0/assets/js/83b912d4.ab8880e8.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[6826],{5680:(t,e,n)=>{n.d(e,{xA:()=>l,yg:()=>f});var o=n(6540);function r(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function s(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(t);e&&(o=o.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,o)}return n}function i(t){for(var e=1;e=0||(r[n]=t[n]);return r}(t,e);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(t);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(t,n)&&(r[n]=t[n])}return r}var c=o.createContext({}),u=function(t){var e=o.useContext(c),n=e;return t&&(n="function"==typeof t?t(e):i(i({},e),t)),n},l=function(t){var e=u(t.components);return o.createElement(c.Provider,{value:e},t.children)},p="mdxType",m={inlineCode:"code",wrapper:function(t){var e=t.children;return o.createElement(o.Fragment,{},e)}},g=o.forwardRef((function(t,e){var n=t.components,r=t.mdxType,s=t.originalType,c=t.parentName,l=a(t,["components","mdxType","originalType","parentName"]),p=u(n),g=r,f=p["".concat(c,".").concat(g)]||p[g]||m[g]||s;return n?o.createElement(f,i(i({ref:e},l),{},{components:n})):o.createElement(f,i({ref:e},l))}));function f(t,e){var n=arguments,r=e&&e.mdxType;if("string"==typeof t||r){var s=n.length,i=new Array(s);i[0]=g;var a={};for(var c in e)hasOwnProperty.call(e,c)&&(a[c]=e[c]);a.originalType=t,a[p]="string"==typeof t?t:r,i[1]=a;for(var u=2;u{n.r(e),n.d(e,{assets:()=>c,contentTitle:()=>i,default:()=>m,frontMatter:()=>s,metadata:()=>a,toc:()=>u});var o=n(8168),r=(n(6540),n(5680));const s={sidebar_position:5},i="CustomFunction",a={unversionedId:"storages/developing-custom-storages/store-traits/custom-function",id:"storages/developing-custom-storages/store-traits/custom-function",title:"CustomFunction",description:"The CustomFunction trait is an optional trait for supporting user-level custom functions. Through the CustomFunction trait, you can retrieve custom functions stored in the storage system. You can choose to implement the CustomFunction trait alone or together with the CustomFunctionMut trait.",source:"@site/docs/storages/developing-custom-storages/store-traits/custom-function.md",sourceDirName:"storages/developing-custom-storages/store-traits",slug:"/storages/developing-custom-storages/store-traits/custom-function",permalink:"/docs/0.16.0/storages/developing-custom-storages/store-traits/custom-function",draft:!1,tags:[],version:"current",sidebarPosition:5,frontMatter:{sidebar_position:5},sidebar:"autoSidebar",previous:{title:"Transaction",permalink:"/docs/0.16.0/storages/developing-custom-storages/store-traits/transaction"},next:{title:"CustomFunctionMut",permalink:"/docs/0.16.0/storages/developing-custom-storages/store-traits/custom-function-mut"}},c={},u=[],l={toc:u},p="wrapper";function m(t){let{components:e,...n}=t;return(0,r.yg)(p,(0,o.A)({},l,n,{components:e,mdxType:"MDXLayout"}),(0,r.yg)("h1",{id:"customfunction"},"CustomFunction"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"CustomFunction")," trait is an optional trait for supporting user-level custom functions. Through the ",(0,r.yg)("inlineCode",{parentName:"p"},"CustomFunction")," trait, you can retrieve custom functions stored in the storage system. You can choose to implement the ",(0,r.yg)("inlineCode",{parentName:"p"},"CustomFunction")," trait alone or together with the ",(0,r.yg)("inlineCode",{parentName:"p"},"CustomFunctionMut")," trait."),(0,r.yg)("p",null,"In some cases, you might want to provide storage-specific functions pre-built and separately available for each storage system. In such cases, you can implement the ",(0,r.yg)("inlineCode",{parentName:"p"},"CustomFunction")," trait and create additional functions stored in advance when using it. To achieve this, the ",(0,r.yg)("inlineCode",{parentName:"p"},"CustomFunction")," and ",(0,r.yg)("inlineCode",{parentName:"p"},"CustomFunctionMut")," traits are provided separately for implementation."),(0,r.yg)("p",null,"There are two methods available:"),(0,r.yg)("ol",null,(0,r.yg)("li",{parentName:"ol"},(0,r.yg)("p",{parentName:"li"},(0,r.yg)("inlineCode",{parentName:"p"},"fetch_function"),": This method retrieves a custom function from the storage system using the provided function name.")),(0,r.yg)("li",{parentName:"ol"},(0,r.yg)("p",{parentName:"li"},(0,r.yg)("inlineCode",{parentName:"p"},"fetch_all_functions"),": This method retrieves all custom functions stored in the storage system."))),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-rust"},"#[async_trait(?Send)]\npub trait CustomFunction {\n async fn fetch_function(&self, _func_name: &str) -> Result>;\n\n async fn fetch_all_functions(&self) -> Result>;\n}\n")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/8417e7a5.dcd6c648.js b/docs/0.16.0/assets/js/8417e7a5.dcd6c648.js new file mode 100644 index 00000000..3693c257 --- /dev/null +++ b/docs/0.16.0/assets/js/8417e7a5.dcd6c648.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[8681],{5680:(e,t,a)=>{a.d(t,{xA:()=>d,yg:()=>g});var n=a(6540);function s(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function r(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function i(e){for(var t=1;t=0||(s[a]=e[a]);return s}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(s[a]=e[a])}return s}var l=n.createContext({}),u=function(e){var t=n.useContext(l),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},d=function(e){var t=u(e.components);return n.createElement(l.Provider,{value:t},e.children)},c="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},h=n.forwardRef((function(e,t){var a=e.components,s=e.mdxType,r=e.originalType,l=e.parentName,d=o(e,["components","mdxType","originalType","parentName"]),c=u(a),h=s,g=c["".concat(l,".").concat(h)]||c[h]||p[h]||r;return a?n.createElement(g,i(i({ref:t},d),{},{components:a})):n.createElement(g,i({ref:t},d))}));function g(e,t){var a=arguments,s=t&&t.mdxType;if("string"==typeof e||s){var r=a.length,i=new Array(r);i[0]=h;var o={};for(var l in t)hasOwnProperty.call(t,l)&&(o[l]=t[l]);o.originalType=e,o[c]="string"==typeof e?e:s,i[1]=o;for(var u=2;u{a.r(t),a.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>p,frontMatter:()=>r,metadata:()=>o,toc:()=>u});var n=a(8168),s=(a(6540),a(5680));const r={title:"Breaking the Boundary between SQL and NoSQL Databases",description:"Breaking the Boundary between SQL and NoSQL Databases",slug:"breaking-the-boundary-between-sql-and-nosql",authors:[{name:"Taehoon Moon",title:"Creator of GlueSQL",url:"https://github.com/panarch",image_url:"https://github.com/panarch.png"}],tags:["sql","database","nosql"]},i="Breaking the Boundary between SQL and NoSQL Databases",o={permalink:"/docs/0.16.0/blog/breaking-the-boundary-between-sql-and-nosql",source:"@site/blog/2023-05-29-breaking-the-boundary.md",title:"Breaking the Boundary between SQL and NoSQL Databases",description:"Breaking the Boundary between SQL and NoSQL Databases",date:"2023-05-29T00:00:00.000Z",formattedDate:"May 29, 2023",tags:[{label:"sql",permalink:"/docs/0.16.0/blog/tags/sql"},{label:"database",permalink:"/docs/0.16.0/blog/tags/database"},{label:"nosql",permalink:"/docs/0.16.0/blog/tags/nosql"}],readingTime:10.055,hasTruncateMarker:!1,authors:[{name:"Taehoon Moon",title:"Creator of GlueSQL",url:"https://github.com/panarch",image_url:"https://github.com/panarch.png",imageURL:"https://github.com/panarch.png"}],frontMatter:{title:"Breaking the Boundary between SQL and NoSQL Databases",description:"Breaking the Boundary between SQL and NoSQL Databases",slug:"breaking-the-boundary-between-sql-and-nosql",authors:[{name:"Taehoon Moon",title:"Creator of GlueSQL",url:"https://github.com/panarch",image_url:"https://github.com/panarch.png",imageURL:"https://github.com/panarch.png"}],tags:["sql","database","nosql"]},prevItem:{title:"Test-Driven Documentation - Automating User Manual Creation in GlueSQL",permalink:"/docs/0.16.0/blog/test-driven-documentation"},nextItem:{title:"Release v0.14",permalink:"/docs/0.16.0/blog/release-v0.14"}},l={authorsImageUrls:[void 0]},u=[{value:"Introduction",id:"introduction",level:2},{value:"The Interface Perspective: SQL & AST Builder",id:"the-interface-perspective-sql--ast-builder",level:2},{value:"Structured & Unstructured Data",id:"structured--unstructured-data",level:2},{value:"Decomposing Database Functionality: Breaking Down SQL and NoSQL Features",id:"decomposing-database-functionality-breaking-down-sql-and-nosql-features",level:2},{value:"Conclusion",id:"conclusion",level:2}],d={toc:u},c="wrapper";function p(e){let{components:t,...a}=e;return(0,s.yg)(c,(0,n.A)({},d,a,{components:t,mdxType:"MDXLayout"}),(0,s.yg)("h2",{id:"introduction"},"Introduction"),(0,s.yg)("p",null,"The divide between SQL and NoSQL databases has often presented challenges in database management. GlueSQL, a unique database maker library, aims to blur this boundary, providing a versatile tool for handling these two distinct types of databases."),(0,s.yg)("p",null,"In this article, we explore how GlueSQL navigates the features of SQL and NoSQL databases, offering an integrated solution that promotes flexibility and efficiency. With its ability to unify disparate database types, GlueSQL heralds a new age of adaptable database creation and management."),(0,s.yg)("h2",{id:"the-interface-perspective-sql--ast-builder"},"The Interface Perspective: SQL & AST Builder"),(0,s.yg)("p",null,"When we talk about SQL databases, it's almost a given that they support SQL - the standard query language. Although there are slight variations between databases, the convenience of using a similar SQL language across multiple databases cannot be overstated. However, from a software engineer's perspective, there's room for improvement. In most software development scenarios, a specific programming language is used. SQL is a separate language, which can cause friction when integrating it into your software. As a result, rather than using raw SQL, many developers employ query builders or ORMs to manipulate SQL conveniently using their preferred programming language. Although it's not efficient to generate SQL using a query builder and then parse it again in the database, it's a practical and effective choice."),(0,s.yg)("p",null,"On the other hand, NoSQL databases offer different mechanisms. Some of them have their own language similar to SQL, but most provide an interface library developed specifically for each programming language. While SQL databases rely on external query builder libraries to provide an interface for each programming language, NoSQL databases mostly develop and offer these libraries themselves. If we discount the convenience of SQL language, this is one of the major factors that make NoSQL databases more comfortable to use. Since query builder libraries supporting SQL databases often cater to multiple SQL databases, they are limited in fully supporting unique features of each database. NoSQL databases, on the other hand, can freely manage their interface libraries without these restrictions."),(0,s.yg)("p",null,"Providing a query interface for each programming language is not a fundamental difference between SQL and NoSQL, but we generally accept it implicitly."),(0,s.yg)("p",null,"Let's see what happens if we break down this boundary, using GlueSQL as an example. As you can see from the SQL postfix, GlueSQL supports SQL and can be classified as an SQL database."),(0,s.yg)("pre",null,(0,s.yg)("code",{parentName:"pre",className:"language-sql"},'CREATE TABLE Glue (id INTEGER, name TEXT);\n\nINSERT INTO Glue VALUES (1, "hello"), (2, "gluesql");\n\nSELECT * FROM Glue WHERE id = 1;\n')),(0,s.yg)("p",null,"However, GlueSQL also supports its own query builder, like a NoSQL database.\n(Currently, only Rust is supported, but we're working on adding support for other languages.)"),(0,s.yg)("pre",null,(0,s.yg)("code",{parentName:"pre",className:"language-rust"},'table("Glue")\n .create_table()\n .add_column("id INTEGER")\n .add_column("name TEXT")\n .execute(glue)\n\ntable("Glue")\n .insert()\n .values(vec![\n vec![num(1), text("hello")],\n vec![num(2), text("gluesql")],\n ])\n .execute(glue)\n .await;\n\ntable("Glue")\n .select()\n .filter(col("id").eq(1))\n .execute(glue)\n .await;\n')),(0,s.yg)("p",null,"Let's reconsider the implicit distinction between SQL and NoSQL. GlueSQL indeed supports SQL, but it also officially develops and offers its own query builder. This query builder is not a secondary tool for SQL. While most SQL query builder libraries ultimately generate SQL strings, GlueSQL's builder directly creates an AST (Abstract Structure Tree) that is used for execution within GlueSQL. Hence, we call it the AST Builder. This means SQL and the AST Builder are two equally supported interfaces in GlueSQL."),(0,s.yg)("p",null,"This also offers an additional advantage:"),(0,s.yg)("pre",null,(0,s.yg)("code",{parentName:"pre",className:"language-rust"},'table("Glue")\n .select()\n // 1.\n .filter(col("id").eq(1))\n // 2.\n .filter("id = 1")\n .execute(glue)\n .await;\n')),(0,s.yg)("p",null,"Because GlueSQL already supports SQL, not only can you use the custom interface in the AST Builder, but you can also use familiar SQL syntax in part. Whether you use ",(0,s.yg)("inlineCode",{parentName:"p"},'col("id").eq(1)')," or ",(0,s.yg)("inlineCode",{parentName:"p"},'"id = 1"'),", you can use it in the way you prefer. The AST Builder interface, although initially unfamiliar, allows a gradual migration similar to writing SQL for your convenience."),(0,s.yg)("p",null,"Thus, we've dismantled one of the implicit distinctions between SQL and NoSQL. However, it's more of an implicit differentiation than a fundamental one. There are more significant design differences that we'll explore next."),(0,s.yg)("h2",{id:"structured--unstructured-data"},"Structured & Unstructured Data"),(0,s.yg)("p",null,"In this section, we'll discuss how SQL and NoSQL handle data. SQL generally deals with structured data, and recently, it's been made to support semi-structured data as well. On the other hand, NoSQL supports schemaless, unstructured data. Then, we'll explain in detail how GlueSQL handles these two types of data. The last part of this section will provide a segue into the next section where we'll discuss the decomposition of database functions."),(0,s.yg)("p",null,"When talking about SQL databases, one aspect is usually considered together: SQL databases have a defined schema."),(0,s.yg)("pre",null,(0,s.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE Foo (\n id INTEGER,\n name TEXT,\n rate FLOAT NULL\n);\n")),(0,s.yg)("p",null,"However, these days, SQL databases tend to support semi-structured data types, such as LIST or JSON. But, supporting completely schemaless, unstructured data is a different matter. SQL databases typically require a minimum schema."),(0,s.yg)("p",null,"What about NoSQL databases? As NoSQL databases vary significantly, we can't make definitive statements. But let's consider a typical document database like MongoDB. Unlike SQL databases, it doesn't enforce a schema. Essentially, you can insert any form of data directly. Often, NoSQL databases support schemaless data, but they lack features that enforce a schema like SQL. They generally support structure via validation methods, rather than structured access."),(0,s.yg)("p",null,"Is there no choice but to distinguish between structured data and unstructured, schemaless data so clearly? GlueSQL is being developed with the goal of being adaptable in various environments. Being forced to choose regarding this schema constraint was quite inconvenient. We started pondering if we couldn't benefit from both aspects - supporting both schema and schemaless data simultaneously, and we eventually found the answer. Let's look at how GlueSQL currently solves this issue through familiar SQL examples."),(0,s.yg)("pre",null,(0,s.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE Names (id INTEGER, name TEXT);\nINSERT INTO Names VALUES (1, 'glue'), (2, 'sql');\n")),(0,s.yg)("p",null,"You can create a regular table with a schema like this. But GlueSQL's choice for creating a schemaless table is as follows:"),(0,s.yg)("pre",null,(0,s.yg)("code",{parentName:"pre",className:"language-sql"},'CREATE TABLE Logs;\nINSERT INTO Logs VALUES\n (\'{ "id": 1, "value": 30 }\'),\n (\'{ "id": 2, "rate": 3.0, "list": [1, 2, 3] }\'),\n (\'{ "id": 3, "rate": 5.0, "value": 100 }\');\n')),(0,s.yg)("p",null,"It creates a table without column definitions! If you do this, GlueSQL recognizes the table as schemaless and processes it internally."),(0,s.yg)("pre",null,(0,s.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT id, rate, list[0] FROM Logs WHERE id = 2;\n")),(0,s.yg)("p",null,"Although the way to create the table was a bit special, using it isn't much different from the regular SQL SELECT statement. Not only can you differentiate between schema and schemaless when creating tables, but you can also use them interchangeably!"),(0,s.yg)("pre",null,(0,s.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT * FROM Names JOIN Logs ON Names.id = Logs.id;\n/*\n| id | list | name | rate | value |\n|----|---------|------|------|-------|\n| 1 | | glue | | 30 |\n| 2 |[1, 2, 3]| sql | 3 | |\n*/\n")),(0,s.yg)("p",null,"Here's an example of querying data by INNER JOINing the Names table, which has a schema, and the Logs table, which is schemaless. GlueSQL has resolved this problem by allowing the internal execution layer to handle both vector-type data, for cases where each row has a defined schema, and map-type data for schemaless cases."),(0,s.yg)("p",null,"Thanks to this, the variety of storage that can be supported through GlueSQL has expanded significantly. If there were previously limitations to supporting NoSQL databases that support schemaless data, that is no longer the case. The reference storage where you can directly experience this schemaless data support is JSON Storage. It offers features that allow you to deal directly with unstructured data like JSON using GlueSQL."),(0,s.yg)("p",null,"If GlueSQL starts from the perspective of an SQL database and expands, by providing the AST Builder directly, it once blurs the boundary, and by supporting unstructured data simultaneously, it knocks down the boundary once more. How do you like it?"),(0,s.yg)("h2",{id:"decomposing-database-functionality-breaking-down-sql-and-nosql-features"},"Decomposing Database Functionality: Breaking Down SQL and NoSQL Features"),(0,s.yg)("p",null,"The distinction between SQL and NoSQL is not just about whether they support unstructured data. Of course, there are examples like unstructured data, which is mainly supported only in NoSQL, but in many cases, SQL databases tend to support more diverse and complex queries. NoSQL often gains other advantages in exchange for reducing the range of query support provided by SQL databases."),(0,s.yg)("p",null,'GlueSQL is ambitious. It has devised a rather interesting method to support all of this through SQL and the AST Builder, with the same interface. When we usually say SQL database, it implicitly assumes that a lot of features have been fully implemented. Create tables by specifying a schema, modify schemas with "alter table", support both clustered and non-clustered indexes, and support transactions. And there\'s so much more. But the functionality that is naturally supported in SQL databases may not be natural in other environments.'),(0,s.yg)("p",null,"Let's think about JSON Storage. GlueSQL's JSON Storage allows you to handle JSON, JSONL files using SQL and the AST Builder. This JSON Storage does not support atomic operations or transactions. Of course, it would be great if it did, but implementing and executing them would be a significant performance burden. In most cases, when you want to simply browse and handle JSONL files, the overhead caused by transactions can be an unnecessary burden. In this case, you want to handle JSON, JSONL files using SQL, but you don't necessarily need transactions."),(0,s.yg)("p",null,"To meet the requirements of these diverse environments, GlueSQL has separated the functionality of what we usually call an SQL database into multiple independent interfaces.\n",(0,s.yg)("inlineCode",{parentName:"p"},"Store"),", ",(0,s.yg)("inlineCode",{parentName:"p"},"StoreMut"),", ",(0,s.yg)("inlineCode",{parentName:"p"},"AlterTable"),", ",(0,s.yg)("inlineCode",{parentName:"p"},"Transaction"),", ..\nThese are just a few of the various storage interfaces that GlueSQL currently supports.\nThe way it works can be summarized like this:\nIf you implement ",(0,s.yg)("inlineCode",{parentName:"p"},"Store"),", you can use ",(0,s.yg)("inlineCode",{parentName:"p"},"SELECT"),".\nAnd if you implement both ",(0,s.yg)("inlineCode",{parentName:"p"},"Store")," and ",(0,s.yg)("inlineCode",{parentName:"p"},"StoreMut"),", you can support quite a number of basic SQL statements including ",(0,s.yg)("inlineCode",{parentName:"p"},"SELECT"),".\nYou can manage tables with ",(0,s.yg)("inlineCode",{parentName:"p"},"CREATE TABLE"),", ",(0,s.yg)("inlineCode",{parentName:"p"},"DROP TABLE"),", and handle data using ",(0,s.yg)("inlineCode",{parentName:"p"},"INSERT"),", ",(0,s.yg)("inlineCode",{parentName:"p"},"UPDATE"),", ",(0,s.yg)("inlineCode",{parentName:"p"},"DELETE")," statements.\nIf you only need to retrieve data, you only need to implement ",(0,s.yg)("inlineCode",{parentName:"p"},"Store"),".\nIf you want to support the ",(0,s.yg)("inlineCode",{parentName:"p"},"ALTER TABLE")," statement, you can additionally implement the ",(0,s.yg)("inlineCode",{parentName:"p"},"AlterTable")," interface.\nThe Transaction interface works the same way.\nThe interesting part is that, except for Store and StoreMut, all other storage interfaces can be implemented independently. GlueSQL allows you to choose and implement only the features you need.\nAnd it's not just about providing interfaces. It also provides integration tests suitable for each situation to verify what you have implemented. You just need to implement the interface and import the corresponding test case for verification."),(0,s.yg)("p",null,"In addition to supporting both structured and unstructured data simultaneously, GlueSQL provides the ability to divide the functionality of a database into multiple independent features and selectively implement them. This allows GlueSQL to be ported to a wide variety of environments without any burden."),(0,s.yg)("h2",{id:"conclusion"},"Conclusion"),(0,s.yg)("p",null,"GlueSQL, while serving as a database that provides its own reference storage, is fundamentally a library designed to simplify the creation of databases. One of the substantial challenges GlueSQL had to overcome in order to support a diverse array of environments was to address the distinctive features that separate conventional SQL databases from NoSQL databases. GlueSQL achieved this through several innovative approaches, managing to support both categories simultaneously despite their significantly different characteristics."),(0,s.yg)("p",null,"It offers support for SQL alongside an AST Builder, and accommodates both structured and unstructured data. Additionally, it decomposes database functionalities into multiple independent features, allowing each environment to selectively implement the functionalities it requires."),(0,s.yg)("p",null,"These unique attributes enable GlueSQL to live up to its 'Glue' prefix by facilitating effortless porting across various environments. While we have been developing it for several years, there is still much ground to cover. However, the fact that we are now able to introduce it publicly attests to our successful technological validation and completion of a demonstrable level of implementation."),(0,s.yg)("p",null,"Through GlueSQL, we hope to provide developers with a unified query interface that can be customized according to their needs, thereby enabling them to produce efficient products more effortlessly. There's a promising future ahead for GlueSQL, and we look forward to its contributions to the technology community."))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/85afcbde.5593c8d3.js b/docs/0.16.0/assets/js/85afcbde.5593c8d3.js new file mode 100644 index 00000000..75dc7fd9 --- /dev/null +++ b/docs/0.16.0/assets/js/85afcbde.5593c8d3.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[2605],{5680:(e,n,t)=>{t.d(n,{xA:()=>p,yg:()=>y});var a=t(6540);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function l(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function i(e){for(var n=1;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var u=a.createContext({}),o=function(e){var n=a.useContext(u),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},p=function(e){var n=o(e.components);return a.createElement(u.Provider,{value:n},e.children)},c="mdxType",g={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},m=a.forwardRef((function(e,n){var t=e.components,r=e.mdxType,l=e.originalType,u=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),c=o(t),m=r,y=c["".concat(u,".").concat(m)]||c[m]||g[m]||l;return t?a.createElement(y,i(i({ref:n},p),{},{components:t})):a.createElement(y,i({ref:n},p))}));function y(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var l=t.length,i=new Array(l);i[0]=m;var s={};for(var u in n)hasOwnProperty.call(n,u)&&(s[u]=n[u]);s.originalType=e,s[c]="string"==typeof e?e:r,i[1]=s;for(var o=2;o{t.r(n),t.d(n,{assets:()=>u,contentTitle:()=>i,default:()=>g,frontMatter:()=>l,metadata:()=>s,toc:()=>o});var a=t(8168),r=(t(6540),t(5680));const l={},i="TAN",s={unversionedId:"sql-syntax/functions/math/tan",id:"sql-syntax/functions/math/tan",title:"TAN",description:"The TAN function is used to calculate the tangent of a number. It takes a single numeric argument (angle in radians) and returns the tangent of that angle.",source:"@site/docs/sql-syntax/functions/math/tan.md",sourceDirName:"sql-syntax/functions/math",slug:"/sql-syntax/functions/math/tan",permalink:"/docs/0.16.0/sql-syntax/functions/math/tan",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"SQRT",permalink:"/docs/0.16.0/sql-syntax/functions/math/sqrt"},next:{title:"EXTRACT",permalink:"/docs/0.16.0/sql-syntax/functions/datetime/extract"}},u={},o=[{value:"Syntax",id:"syntax",level:2},{value:"Examples",id:"examples",level:2},{value:"Example 1: Using TAN with float values",id:"example-1-using-tan-with-float-values",level:3},{value:"Example 2: Using TAN with NULL values",id:"example-2-using-tan-with-null-values",level:3},{value:"Errors",id:"errors",level:2},{value:"Example 3: Using TAN with non-numeric values",id:"example-3-using-tan-with-non-numeric-values",level:3},{value:"Example 4: Using TAN with multiple arguments",id:"example-4-using-tan-with-multiple-arguments",level:3}],p={toc:o},c="wrapper";function g(e){let{components:n,...t}=e;return(0,r.yg)(c,(0,a.A)({},p,t,{components:n,mdxType:"MDXLayout"}),(0,r.yg)("h1",{id:"tan"},"TAN"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"TAN")," function is used to calculate the tangent of a number. It takes a single numeric argument (angle in radians) and returns the tangent of that angle."),(0,r.yg)("h2",{id:"syntax"},"Syntax"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"TAN(value)\n")),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"value"),": A numeric expression (angle in radians) for which the tangent is to be calculated.")),(0,r.yg)("h2",{id:"examples"},"Examples"),(0,r.yg)("p",null,"Let's consider a table named ",(0,r.yg)("inlineCode",{parentName:"p"},"SingleItem")," with the following schema:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE SingleItem (id INTEGER);\n")),(0,r.yg)("p",null,"Insert a row into the ",(0,r.yg)("inlineCode",{parentName:"p"},"SingleItem")," table:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO SingleItem VALUES (0);\n")),(0,r.yg)("h3",{id:"example-1-using-tan-with-float-values"},"Example 1: Using TAN with float values"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT TAN(0.5) AS tan1, TAN(1) AS tan2 FROM SingleItem;\n")),(0,r.yg)("p",null,"Result:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre"}," tan1 | tan2\n------------+---------------\n 0.54630249 | 1.557407725\n")),(0,r.yg)("h3",{id:"example-2-using-tan-with-null-values"},"Example 2: Using TAN with NULL values"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT TAN(NULL) AS tan FROM SingleItem;\n")),(0,r.yg)("p",null,"Result:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre"}," tan\n-------\n (null)\n")),(0,r.yg)("h2",{id:"errors"},"Errors"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"TAN")," function requires a numeric value as its argument. Using non-numeric values or more than one argument will result in an error."),(0,r.yg)("h3",{id:"example-3-using-tan-with-non-numeric-values"},"Example 3: Using TAN with non-numeric values"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT TAN('string') AS tan FROM SingleItem;\n")),(0,r.yg)("p",null,"Error: Function requires a numeric value."),(0,r.yg)("h3",{id:"example-4-using-tan-with-multiple-arguments"},"Example 4: Using TAN with multiple arguments"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT TAN(1.0, 2.0) AS tan FROM SingleItem;\n")),(0,r.yg)("p",null,"Error: Function expects 1 argument, but 2 were provided."))}g.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/86a1f821.7ee13ee9.js b/docs/0.16.0/assets/js/86a1f821.7ee13ee9.js new file mode 100644 index 00000000..54159466 --- /dev/null +++ b/docs/0.16.0/assets/js/86a1f821.7ee13ee9.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[9186],{5680:(e,t,a)=>{a.d(t,{xA:()=>u,yg:()=>y});var n=a(6540);function l(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function i(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function r(e){for(var t=1;t=0||(l[a]=e[a]);return l}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(l[a]=e[a])}return l}var o=n.createContext({}),m=function(e){var t=n.useContext(o),a=t;return e&&(a="function"==typeof e?e(t):r(r({},t),e)),a},u=function(e){var t=m(e.components);return n.createElement(o.Provider,{value:t},e.children)},c="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var a=e.components,l=e.mdxType,i=e.originalType,o=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),c=m(a),d=l,y=c["".concat(o,".").concat(d)]||c[d]||p[d]||i;return a?n.createElement(y,r(r({ref:t},u),{},{components:a})):n.createElement(y,r({ref:t},u))}));function y(e,t){var a=arguments,l=t&&t.mdxType;if("string"==typeof e||l){var i=a.length,r=new Array(i);r[0]=d;var s={};for(var o in t)hasOwnProperty.call(t,o)&&(s[o]=t[o]);s.originalType=e,s[c]="string"==typeof e?e:l,r[1]=s;for(var m=2;m{a.r(t),a.d(t,{assets:()=>o,contentTitle:()=>r,default:()=>p,frontMatter:()=>i,metadata:()=>s,toc:()=>m});var n=a(8168),l=(a(6540),a(5680));const i={sidebar_position:1},r="CREATE TABLE",s={unversionedId:"sql-syntax/statements/data-definition/create-table",id:"sql-syntax/statements/data-definition/create-table",title:"CREATE TABLE",description:"The CREATE TABLE statement is a fundamental SQL command used to create a new table in a database. Tables are the primary structure in databases, as they hold the data organized in rows and columns. In this document, we'll explain the syntax and usage of the CREATE TABLE statement, including the IF NOT EXISTS clause.",source:"@site/docs/sql-syntax/statements/data-definition/create-table.md",sourceDirName:"sql-syntax/statements/data-definition",slug:"/sql-syntax/statements/data-definition/create-table",permalink:"/docs/0.16.0/sql-syntax/statements/data-definition/create-table",draft:!1,tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"autoSidebar",previous:{title:"Schemaless Data",permalink:"/docs/0.16.0/sql-syntax/statements/querying/schemaless"},next:{title:"DROP TABLE",permalink:"/docs/0.16.0/sql-syntax/statements/data-definition/drop-table"}},o={},m=[{value:"Syntax",id:"syntax",level:2},{value:"CREATE TABLE AS SELECT (CTAS)",id:"create-table-as-select-ctas",level:2},{value:"Example",id:"example",level:2},{value:"Example with CTAS",id:"example-with-ctas",level:2},{value:"Constraints",id:"constraints",level:2},{value:"Summary",id:"summary",level:2}],u={toc:m},c="wrapper";function p(e){let{components:t,...a}=e;return(0,l.yg)(c,(0,n.A)({},u,a,{components:t,mdxType:"MDXLayout"}),(0,l.yg)("h1",{id:"create-table"},"CREATE TABLE"),(0,l.yg)("p",null,"The ",(0,l.yg)("inlineCode",{parentName:"p"},"CREATE TABLE")," statement is a fundamental SQL command used to create a new table in a database. Tables are the primary structure in databases, as they hold the data organized in rows and columns. In this document, we'll explain the syntax and usage of the ",(0,l.yg)("inlineCode",{parentName:"p"},"CREATE TABLE")," statement, including the ",(0,l.yg)("inlineCode",{parentName:"p"},"IF NOT EXISTS")," clause."),(0,l.yg)("h2",{id:"syntax"},"Syntax"),(0,l.yg)("p",null,"The basic syntax for the ",(0,l.yg)("inlineCode",{parentName:"p"},"CREATE TABLE")," statement is as follows:"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE [IF NOT EXISTS] table_name (\n column1 datatype constraint,\n column2 datatype constraint,\n column3 datatype constraint,\n ...\n);\n")),(0,l.yg)("ul",null,(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("inlineCode",{parentName:"li"},"IF NOT EXISTS"),": This optional clause allows you to check if a table with the same name already exists in the database. If it exists, the command does nothing; otherwise, it creates a new table."),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("inlineCode",{parentName:"li"},"table_name"),": The name of the table you want to create."),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("inlineCode",{parentName:"li"},"column"),": Each column in the table is defined by its name, datatype, and optional constraints."),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("inlineCode",{parentName:"li"},"datatype"),": The type of data that the column will store (e.g., INTEGER, TEXT, DATE, etc.)."),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("inlineCode",{parentName:"li"},"constraint"),": Optional constraints to enforce rules on the data stored in the column (e.g., PRIMARY KEY, NOT NULL, UNIQUE, etc.).")),(0,l.yg)("h2",{id:"create-table-as-select-ctas"},"CREATE TABLE AS SELECT (CTAS)"),(0,l.yg)("p",null,"You can also create a new table based on the result of a SELECT statement using the CTAS syntax:"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE table_name AS SELECT * FROM other_table;\n")),(0,l.yg)("ul",null,(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("inlineCode",{parentName:"li"},"table_name"),": The name of the new table to be created."),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("inlineCode",{parentName:"li"},"other_table"),": The existing table from which the data will be selected.")),(0,l.yg)("p",null,"This command creates a new table with the same column structure as the source table and populates it with the data returned by the SELECT statement. The SELECT statement in this example uses the wildcard *, meaning that all columns from the source table will be included in the new table."),(0,l.yg)("h2",{id:"example"},"Example"),(0,l.yg)("p",null,"Let's create a simple table called ",(0,l.yg)("inlineCode",{parentName:"p"},"employees")," with the following columns:"),(0,l.yg)("ul",null,(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("inlineCode",{parentName:"li"},"id"),": A unique identifier for each employee (integer, primary key)."),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("inlineCode",{parentName:"li"},"first_name"),": The employee's first name (text, not null)."),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("inlineCode",{parentName:"li"},"last_name"),": The employee's last name (text, not null)."),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("inlineCode",{parentName:"li"},"email"),": The employee's email address (text, unique)."),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("inlineCode",{parentName:"li"},"hire_date"),": The date the employee was hired (date).")),(0,l.yg)("p",null,"The SQL statement to create this table, using the ",(0,l.yg)("inlineCode",{parentName:"p"},"IF NOT EXISTS")," clause, would look like this:"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE IF NOT EXISTS employees (\n id INTEGER PRIMARY KEY,\n first_name TEXT NOT NULL,\n last_name TEXT NOT NULL,\n email TEXT UNIQUE,\n hire_date DATE\n);\n")),(0,l.yg)("h2",{id:"example-with-ctas"},"Example with CTAS"),(0,l.yg)("p",null,"Assuming there is an existing table named employees_backup, you can create a new table called employees_copy with the same structure and data using CTAS:"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE employees_copy AS SELECT * FROM employees_backup;\n")),(0,l.yg)("h2",{id:"constraints"},"Constraints"),(0,l.yg)("p",null,"Constraints are rules that you can apply to columns in a table to control the data being stored. Some common constraints are:"),(0,l.yg)("ul",null,(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("inlineCode",{parentName:"li"},"PRIMARY KEY"),": Uniquely identifies each row in the table."),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("inlineCode",{parentName:"li"},"NOT NULL"),": Ensures the column cannot store a NULL value."),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("inlineCode",{parentName:"li"},"UNIQUE"),": Ensures all values in the column are unique."),(0,l.yg)("li",{parentName:"ul"},(0,l.yg)("inlineCode",{parentName:"li"},"DEFAULT"),": Sets a default value for the column when no value is specified.")),(0,l.yg)("h2",{id:"summary"},"Summary"),(0,l.yg)("p",null,"The ",(0,l.yg)("inlineCode",{parentName:"p"},"CREATE TABLE")," statement is an essential SQL command that allows you to create tables in a database. It requires a table name and one or more column definitions with their respective datatypes and optional constraints. The ",(0,l.yg)("inlineCode",{parentName:"p"},"IF NOT EXISTS")," clause can be used to prevent creating duplicate tables. By understanding the ",(0,l.yg)("inlineCode",{parentName:"p"},"CREATE TABLE")," syntax, you can define the structure of your tables and ensure the data stored in them is accurate and reliable."))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/8809.44c4a575.js b/docs/0.16.0/assets/js/8809.44c4a575.js new file mode 100644 index 00000000..3f82ba28 --- /dev/null +++ b/docs/0.16.0/assets/js/8809.44c4a575.js @@ -0,0 +1 @@ +(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[8809],{5680:(e,t,n)=>{"use strict";n.d(t,{xA:()=>u,yg:()=>f});var o=n(6540);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function c(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var i=o.createContext({}),s=function(e){var t=o.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):c(c({},t),e)),n},u=function(e){var t=s(e.components);return o.createElement(i.Provider,{value:t},e.children)},m="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},p=o.forwardRef((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,i=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),m=s(n),p=a,f=m["".concat(i,".").concat(p)]||m[p]||d[p]||r;return n?o.createElement(f,c(c({ref:t},u),{},{components:n})):o.createElement(f,c({ref:t},u))}));function f(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,c=new Array(r);c[0]=p;var l={};for(var i in t)hasOwnProperty.call(t,i)&&(l[i]=t[i]);l.originalType=e,l[m]="string"==typeof e?e:a,c[1]=l;for(var s=2;s{"use strict";n.d(t,{A:()=>u});var o=n(6540),a=n(1312),r=n(7559),c=n(8168),l=n(53);const i={iconEdit:"iconEdit_Z9Sw"};function s(e){let{className:t,...n}=e;return o.createElement("svg",(0,c.A)({fill:"currentColor",height:"20",width:"20",viewBox:"0 0 40 40",className:(0,l.A)(i.iconEdit,t),"aria-hidden":"true"},n),o.createElement("g",null,o.createElement("path",{d:"m34.5 11.7l-3 3.1-6.3-6.3 3.1-3q0.5-0.5 1.2-0.5t1.1 0.5l3.9 3.9q0.5 0.4 0.5 1.1t-0.5 1.2z m-29.5 17.1l18.4-18.5 6.3 6.3-18.4 18.4h-6.3v-6.2z"})))}function u(e){let{editUrl:t}=e;return o.createElement("a",{href:t,target:"_blank",rel:"noreferrer noopener",className:r.G.common.editThisPage},o.createElement(s,null),o.createElement(a.A,{id:"theme.common.editThisPage",description:"The link label to edit the current page"},"Edit this page"))}},1107:(e,t,n)=>{"use strict";n.d(t,{A:()=>u});var o=n(8168),a=n(6540),r=n(53),c=n(1312),l=n(6342),i=n(5489);const s={anchorWithStickyNavbar:"anchorWithStickyNavbar_LWe7",anchorWithHideOnScrollNavbar:"anchorWithHideOnScrollNavbar_WYt5"};function u(e){let{as:t,id:n,...u}=e;const{navbar:{hideOnScroll:m}}=(0,l.p)();if("h1"===t||!n)return a.createElement(t,(0,o.A)({},u,{id:void 0}));const d=(0,c.T)({id:"theme.common.headingLinkTitle",message:"Direct link to {heading}",description:"Title for link to heading"},{heading:"string"==typeof u.children?u.children:n});return a.createElement(t,(0,o.A)({},u,{className:(0,r.A)("anchor",m?s.anchorWithHideOnScrollNavbar:s.anchorWithStickyNavbar,u.className),id:n}),u.children,a.createElement(i.A,{className:"hash-link",to:`#${n}`,"aria-label":d,title:d},"\u200b"))}},7780:(e,t,n)=>{"use strict";n.d(t,{A:()=>ye});var o=n(6540),a=n(5680),r=n(8168),c=n(5260);var l=n(2303),i=n(53),s=n(5293),u=n(6342);function m(){const{prism:e}=(0,u.p)(),{colorMode:t}=(0,s.G)(),n=e.theme,o=e.darkTheme||n;return"dark"===t?o:n}var d=n(7559),p=n(8426),f=n.n(p);const g=/title=(?["'])(?.*?)\1/,h=/\{(?<range>[\d,-]+)\}/,y={js:{start:"\\/\\/",end:""},jsBlock:{start:"\\/\\*",end:"\\*\\/"},jsx:{start:"\\{\\s*\\/\\*",end:"\\*\\/\\s*\\}"},bash:{start:"#",end:""},html:{start:"\x3c!--",end:"--\x3e"}};function b(e,t){const n=e.map((e=>{const{start:n,end:o}=y[e];return`(?:${n}\\s*(${t.flatMap((e=>[e.line,e.block?.start,e.block?.end].filter(Boolean))).join("|")})\\s*${o})`})).join("|");return new RegExp(`^\\s*(?:${n})\\s*$`)}function v(e,t){let n=e.replace(/\n$/,"");const{language:o,magicComments:a,metastring:r}=t;if(r&&h.test(r)){const e=r.match(h).groups.range;if(0===a.length)throw new Error(`A highlight range has been given in code block's metastring (\`\`\` ${r}), but no magic comment config is available. Docusaurus applies the first magic comment entry's className for metastring ranges.`);const t=a[0].className,o=f()(e).filter((e=>e>0)).map((e=>[e-1,[t]]));return{lineClassNames:Object.fromEntries(o),code:n}}if(void 0===o)return{lineClassNames:{},code:n};const c=function(e,t){switch(e){case"js":case"javascript":case"ts":case"typescript":return b(["js","jsBlock"],t);case"jsx":case"tsx":return b(["js","jsBlock","jsx"],t);case"html":return b(["js","jsBlock","html"],t);case"python":case"py":case"bash":return b(["bash"],t);case"markdown":case"md":return b(["html","jsx","bash"],t);default:return b(Object.keys(y),t)}}(o,a),l=n.split("\n"),i=Object.fromEntries(a.map((e=>[e.className,{start:0,range:""}]))),s=Object.fromEntries(a.filter((e=>e.line)).map((e=>{let{className:t,line:n}=e;return[n,t]}))),u=Object.fromEntries(a.filter((e=>e.block)).map((e=>{let{className:t,block:n}=e;return[n.start,t]}))),m=Object.fromEntries(a.filter((e=>e.block)).map((e=>{let{className:t,block:n}=e;return[n.end,t]})));for(let p=0;p<l.length;){const e=l[p].match(c);if(!e){p+=1;continue}const t=e.slice(1).find((e=>void 0!==e));s[t]?i[s[t]].range+=`${p},`:u[t]?i[u[t]].start=p:m[t]&&(i[m[t]].range+=`${i[m[t]].start}-${p-1},`),l.splice(p,1)}n=l.join("\n");const d={};return Object.entries(i).forEach((e=>{let[t,{range:n}]=e;f()(n).forEach((e=>{d[e]??=[],d[e].push(t)}))})),{lineClassNames:d,code:n}}const E={codeBlockContainer:"codeBlockContainer_Ckt0"};function k(e){let{as:t,...n}=e;const a=function(e){const t={color:"--prism-color",backgroundColor:"--prism-background-color"},n={};return Object.entries(e.plain).forEach((e=>{let[o,a]=e;const r=t[o];r&&"string"==typeof a&&(n[r]=a)})),n}(m());return o.createElement(t,(0,r.A)({},n,{style:a,className:(0,i.A)(n.className,E.codeBlockContainer,d.G.common.codeBlock)}))}const N={codeBlockContent:"codeBlockContent_biex",codeBlockTitle:"codeBlockTitle_Ktv7",codeBlock:"codeBlock_bY9V",codeBlockStandalone:"codeBlockStandalone_MEMb",codeBlockLines:"codeBlockLines_e6Vv",codeBlockLinesWithNumbering:"codeBlockLinesWithNumbering_o6Pm",buttonGroup:"buttonGroup__atx"};function A(e){let{children:t,className:n}=e;return o.createElement(k,{as:"pre",tabIndex:0,className:(0,i.A)(N.codeBlockStandalone,"thin-scrollbar",n)},o.createElement("code",{className:N.codeBlockLines},t))}var C=n(9532);const w={attributes:!0,characterData:!0,childList:!0,subtree:!0};function B(e,t){const[n,a]=(0,o.useState)(),r=(0,o.useCallback)((()=>{a(e.current?.closest("[role=tabpanel][hidden]"))}),[e,a]);(0,o.useEffect)((()=>{r()}),[r]),function(e,t,n){void 0===n&&(n=w);const a=(0,C._q)(t),r=(0,C.Be)(n);(0,o.useEffect)((()=>{const t=new MutationObserver(a);return e&&t.observe(e,r),()=>t.disconnect()}),[e,a,r])}(n,(e=>{e.forEach((e=>{"attributes"===e.type&&"hidden"===e.attributeName&&(t(),r())}))}),{attributes:!0,characterData:!1,childList:!1,subtree:!1})}const T={plain:{backgroundColor:"#2a2734",color:"#9a86fd"},styles:[{types:["comment","prolog","doctype","cdata","punctuation"],style:{color:"#6c6783"}},{types:["namespace"],style:{opacity:.7}},{types:["tag","operator","number"],style:{color:"#e09142"}},{types:["property","function"],style:{color:"#9a86fd"}},{types:["tag-id","selector","atrule-id"],style:{color:"#eeebff"}},{types:["attr-name"],style:{color:"#c4b9fe"}},{types:["boolean","string","entity","url","attr-value","keyword","control","directive","unit","statement","regex","atrule","placeholder","variable"],style:{color:"#ffcc99"}},{types:["deleted"],style:{textDecorationLine:"line-through"}},{types:["inserted"],style:{textDecorationLine:"underline"}},{types:["italic"],style:{fontStyle:"italic"}},{types:["important","bold"],style:{fontWeight:"bold"}},{types:["important"],style:{color:"#c4b9fe"}}]};var L={Prism:n(1258).A,theme:T};function j(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function _(){return _=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var o in n)Object.prototype.hasOwnProperty.call(n,o)&&(e[o]=n[o])}return e},_.apply(this,arguments)}var x=/\r\n|\r|\n/,O=function(e){0===e.length?e.push({types:["plain"],content:"\n",empty:!0}):1===e.length&&""===e[0].content&&(e[0].content="\n",e[0].empty=!0)},S=function(e,t){var n=e.length;return n>0&&e[n-1]===t?e:e.concat(t)};function P(e,t){var n={};for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&-1===t.indexOf(o)&&(n[o]=e[o]);return n}var z=function(e){function t(){for(var t=this,n=[],o=arguments.length;o--;)n[o]=arguments[o];e.apply(this,n),j(this,"getThemeDict",(function(e){if(void 0!==t.themeDict&&e.theme===t.prevTheme&&e.language===t.prevLanguage)return t.themeDict;t.prevTheme=e.theme,t.prevLanguage=e.language;var n=e.theme?function(e,t){var n=e.plain,o=Object.create(null),a=e.styles.reduce((function(e,n){var o=n.languages,a=n.style;return o&&!o.includes(t)||n.types.forEach((function(t){var n=_({},e[t],a);e[t]=n})),e}),o);return a.root=n,a.plain=_({},n,{backgroundColor:null}),a}(e.theme,e.language):void 0;return t.themeDict=n})),j(this,"getLineProps",(function(e){var n=e.key,o=e.className,a=e.style,r=_({},P(e,["key","className","style","line"]),{className:"token-line",style:void 0,key:void 0}),c=t.getThemeDict(t.props);return void 0!==c&&(r.style=c.plain),void 0!==a&&(r.style=void 0!==r.style?_({},r.style,a):a),void 0!==n&&(r.key=n),o&&(r.className+=" "+o),r})),j(this,"getStyleForToken",(function(e){var n=e.types,o=e.empty,a=n.length,r=t.getThemeDict(t.props);if(void 0!==r){if(1===a&&"plain"===n[0])return o?{display:"inline-block"}:void 0;if(1===a&&!o)return r[n[0]];var c=o?{display:"inline-block"}:{},l=n.map((function(e){return r[e]}));return Object.assign.apply(Object,[c].concat(l))}})),j(this,"getTokenProps",(function(e){var n=e.key,o=e.className,a=e.style,r=e.token,c=_({},P(e,["key","className","style","token"]),{className:"token "+r.types.join(" "),children:r.content,style:t.getStyleForToken(r),key:void 0});return void 0!==a&&(c.style=void 0!==c.style?_({},c.style,a):a),void 0!==n&&(c.key=n),o&&(c.className+=" "+o),c})),j(this,"tokenize",(function(e,t,n,o){var a={code:t,grammar:n,language:o,tokens:[]};e.hooks.run("before-tokenize",a);var r=a.tokens=e.tokenize(a.code,a.grammar,a.language);return e.hooks.run("after-tokenize",a),r}))}return e&&(t.__proto__=e),t.prototype=Object.create(e&&e.prototype),t.prototype.constructor=t,t.prototype.render=function(){var e=this.props,t=e.Prism,n=e.language,o=e.code,a=e.children,r=this.getThemeDict(this.props),c=t.languages[n];return a({tokens:function(e){for(var t=[[]],n=[e],o=[0],a=[e.length],r=0,c=0,l=[],i=[l];c>-1;){for(;(r=o[c]++)<a[c];){var s=void 0,u=t[c],m=n[c][r];if("string"==typeof m?(u=c>0?u:["plain"],s=m):(u=S(u,m.type),m.alias&&(u=S(u,m.alias)),s=m.content),"string"==typeof s){var d=s.split(x),p=d.length;l.push({types:u,content:d[0]});for(var f=1;f<p;f++)O(l),i.push(l=[]),l.push({types:u,content:d[f]})}else c++,t.push(u),n.push(s),o.push(0),a.push(s.length)}c--,t.pop(),n.pop(),o.pop(),a.pop()}return O(l),i}(void 0!==c?this.tokenize(t,o,c,n):[o]),className:"prism-code language-"+n,style:void 0!==r?r.root:{},getLineProps:this.getLineProps,getTokenProps:this.getTokenProps})},t}(o.Component);const W=z,M={codeLine:"codeLine_lJS_",codeLineNumber:"codeLineNumber_Tfdd",codeLineContent:"codeLineContent_feaV"};function H(e){let{line:t,classNames:n,showLineNumbers:a,getLineProps:c,getTokenProps:l}=e;1===t.length&&"\n"===t[0].content&&(t[0].content="");const s=c({line:t,className:(0,i.A)(n,a&&M.codeLine)}),u=t.map(((e,t)=>o.createElement("span",(0,r.A)({key:t},l({token:e,key:t})))));return o.createElement("span",s,a?o.createElement(o.Fragment,null,o.createElement("span",{className:M.codeLineNumber}),o.createElement("span",{className:M.codeLineContent},u)):u,o.createElement("br",null))}var D=n(1312);function I(e){return o.createElement("svg",(0,r.A)({viewBox:"0 0 24 24"},e),o.createElement("path",{fill:"currentColor",d:"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"}))}function V(e){return o.createElement("svg",(0,r.A)({viewBox:"0 0 24 24"},e),o.createElement("path",{fill:"currentColor",d:"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"}))}const R={copyButtonCopied:"copyButtonCopied_obH4",copyButtonIcons:"copyButtonIcons_eSgA",copyButtonIcon:"copyButtonIcon_y97N",copyButtonSuccessIcon:"copyButtonSuccessIcon_LjdS"};function $(e){let{code:t,className:n}=e;const[a,r]=(0,o.useState)(!1),c=(0,o.useRef)(void 0),l=(0,o.useCallback)((()=>{!function(e,t){let{target:n=document.body}=void 0===t?{}:t;if("string"!=typeof e)throw new TypeError(`Expected parameter \`text\` to be a \`string\`, got \`${typeof e}\`.`);const o=document.createElement("textarea"),a=document.activeElement;o.value=e,o.setAttribute("readonly",""),o.style.contain="strict",o.style.position="absolute",o.style.left="-9999px",o.style.fontSize="12pt";const r=document.getSelection(),c=r.rangeCount>0&&r.getRangeAt(0);n.append(o),o.select(),o.selectionStart=0,o.selectionEnd=e.length;let l=!1;try{l=document.execCommand("copy")}catch{}o.remove(),c&&(r.removeAllRanges(),r.addRange(c)),a&&a.focus()}(t),r(!0),c.current=window.setTimeout((()=>{r(!1)}),1e3)}),[t]);return(0,o.useEffect)((()=>()=>window.clearTimeout(c.current)),[]),o.createElement("button",{type:"button","aria-label":a?(0,D.T)({id:"theme.CodeBlock.copied",message:"Copied",description:"The copied button label on code blocks"}):(0,D.T)({id:"theme.CodeBlock.copyButtonAriaLabel",message:"Copy code to clipboard",description:"The ARIA label for copy code blocks button"}),title:(0,D.T)({id:"theme.CodeBlock.copy",message:"Copy",description:"The copy button label on code blocks"}),className:(0,i.A)("clean-btn",n,R.copyButton,a&&R.copyButtonCopied),onClick:l},o.createElement("span",{className:R.copyButtonIcons,"aria-hidden":"true"},o.createElement(I,{className:R.copyButtonIcon}),o.createElement(V,{className:R.copyButtonSuccessIcon})))}function G(e){return o.createElement("svg",(0,r.A)({viewBox:"0 0 24 24"},e),o.createElement("path",{fill:"currentColor",d:"M4 19h6v-2H4v2zM20 5H4v2h16V5zm-3 6H4v2h13.25c1.1 0 2 .9 2 2s-.9 2-2 2H15v-2l-3 3l3 3v-2h2c2.21 0 4-1.79 4-4s-1.79-4-4-4z"}))}const q={wordWrapButtonIcon:"wordWrapButtonIcon_Bwma",wordWrapButtonEnabled:"wordWrapButtonEnabled_EoeP"};function F(e){let{className:t,onClick:n,isEnabled:a}=e;const r=(0,D.T)({id:"theme.CodeBlock.wordWrapToggle",message:"Toggle word wrap",description:"The title attribute for toggle word wrapping button of code block lines"});return o.createElement("button",{type:"button",onClick:n,className:(0,i.A)("clean-btn",t,a&&q.wordWrapButtonEnabled),"aria-label":r,title:r},o.createElement(G,{className:q.wordWrapButtonIcon,"aria-hidden":"true"}))}function U(e){let{children:t,className:n="",metastring:a,title:c,showLineNumbers:l,language:s}=e;const{prism:{defaultLanguage:d,magicComments:p}}=(0,u.p)(),f=s??function(e){const t=e.split(" ").find((e=>e.startsWith("language-")));return t?.replace(/language-/,"")}(n)??d,h=m(),y=function(){const[e,t]=(0,o.useState)(!1),[n,a]=(0,o.useState)(!1),r=(0,o.useRef)(null),c=(0,o.useCallback)((()=>{const n=r.current.querySelector("code");e?n.removeAttribute("style"):(n.style.whiteSpace="pre-wrap",n.style.overflowWrap="anywhere"),t((e=>!e))}),[r,e]),l=(0,o.useCallback)((()=>{const{scrollWidth:e,clientWidth:t}=r.current,n=e>t||r.current.querySelector("code").hasAttribute("style");a(n)}),[r]);return B(r,l),(0,o.useEffect)((()=>{l()}),[e,l]),(0,o.useEffect)((()=>(window.addEventListener("resize",l,{passive:!0}),()=>{window.removeEventListener("resize",l)})),[l]),{codeBlockRef:r,isEnabled:e,isCodeScrollable:n,toggle:c}}(),b=function(e){return e?.match(g)?.groups.title??""}(a)||c,{lineClassNames:E,code:A}=v(t,{metastring:a,language:f,magicComments:p}),C=l??function(e){return Boolean(e?.includes("showLineNumbers"))}(a);return o.createElement(k,{as:"div",className:(0,i.A)(n,f&&!n.includes(`language-${f}`)&&`language-${f}`)},b&&o.createElement("div",{className:N.codeBlockTitle},b),o.createElement("div",{className:N.codeBlockContent},o.createElement(W,(0,r.A)({},L,{theme:h,code:A,language:f??"text"}),(e=>{let{className:t,tokens:n,getLineProps:a,getTokenProps:r}=e;return o.createElement("pre",{tabIndex:0,ref:y.codeBlockRef,className:(0,i.A)(t,N.codeBlock,"thin-scrollbar")},o.createElement("code",{className:(0,i.A)(N.codeBlockLines,C&&N.codeBlockLinesWithNumbering)},n.map(((e,t)=>o.createElement(H,{key:t,line:e,getLineProps:a,getTokenProps:r,classNames:E[t],showLineNumbers:C})))))})),o.createElement("div",{className:N.buttonGroup},(y.isEnabled||y.isCodeScrollable)&&o.createElement(F,{className:N.codeButton,onClick:()=>y.toggle(),isEnabled:y.isEnabled}),o.createElement($,{className:N.codeButton,code:A}))))}function Y(e){let{children:t,...n}=e;const a=(0,l.A)(),c=function(e){return o.Children.toArray(e).some((e=>(0,o.isValidElement)(e)))?e:Array.isArray(e)?e.join(""):e}(t),i="string"==typeof c?U:A;return o.createElement(i,(0,r.A)({key:String(a)},n),c)}var Z=n(5489);var Q=n(1422);const X={details:"details_lb9f",isBrowser:"isBrowser_bmU9",collapsibleContent:"collapsibleContent_i85q"};function J(e){return!!e&&("SUMMARY"===e.tagName||J(e.parentElement))}function K(e,t){return!!e&&(e===t||K(e.parentElement,t))}function ee(e){let{summary:t,children:n,...a}=e;const c=(0,l.A)(),s=(0,o.useRef)(null),{collapsed:u,setCollapsed:m}=(0,Q.u)({initialState:!a.open}),[d,p]=(0,o.useState)(a.open),f=o.isValidElement(t)?t:o.createElement("summary",null,t??"Details");return o.createElement("details",(0,r.A)({},a,{ref:s,open:d,"data-collapsed":u,className:(0,i.A)(X.details,c&&X.isBrowser,a.className),onMouseDown:e=>{J(e.target)&&e.detail>1&&e.preventDefault()},onClick:e=>{e.stopPropagation();const t=e.target;J(t)&&K(t,s.current)&&(e.preventDefault(),u?(m(!1),p(!0)):m(!0))}}),f,o.createElement(Q.N,{lazy:!1,collapsed:u,disableSSRStyle:!0,onCollapseTransitionEnd:e=>{m(e),p(!e)}},o.createElement("div",{className:X.collapsibleContent},n)))}const te={details:"details_b_Ee"},ne="alert alert--info";function oe(e){let{...t}=e;return o.createElement(ee,(0,r.A)({},t,{className:(0,i.A)(ne,te.details,t.className)}))}var ae=n(1107);function re(e){return o.createElement(ae.A,e)}const ce={containsTaskList:"containsTaskList_mC6p"};function le(e){if(void 0!==e)return(0,i.A)(e,e?.includes("contains-task-list")&&ce.containsTaskList)}const ie={img:"img_ev3q"};const se="admonition_LlT9",ue="admonitionHeading_tbUL",me="admonitionIcon_kALy",de="admonitionContent_S0QG";const pe={note:{infimaClassName:"secondary",iconComponent:function(){return o.createElement("svg",{viewBox:"0 0 14 16"},o.createElement("path",{fillRule:"evenodd",d:"M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"}))},label:o.createElement(D.A,{id:"theme.admonition.note",description:"The default label used for the Note admonition (:::note)"},"note")},tip:{infimaClassName:"success",iconComponent:function(){return o.createElement("svg",{viewBox:"0 0 12 16"},o.createElement("path",{fillRule:"evenodd",d:"M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"}))},label:o.createElement(D.A,{id:"theme.admonition.tip",description:"The default label used for the Tip admonition (:::tip)"},"tip")},danger:{infimaClassName:"danger",iconComponent:function(){return o.createElement("svg",{viewBox:"0 0 12 16"},o.createElement("path",{fillRule:"evenodd",d:"M5.05.31c.81 2.17.41 3.38-.52 4.31C3.55 5.67 1.98 6.45.9 7.98c-1.45 2.05-1.7 6.53 3.53 7.7-2.2-1.16-2.67-4.52-.3-6.61-.61 2.03.53 3.33 1.94 2.86 1.39-.47 2.3.53 2.27 1.67-.02.78-.31 1.44-1.13 1.81 3.42-.59 4.78-3.42 4.78-5.56 0-2.84-2.53-3.22-1.25-5.61-1.52.13-2.03 1.13-1.89 2.75.09 1.08-1.02 1.8-1.86 1.33-.67-.41-.66-1.19-.06-1.78C8.18 5.31 8.68 2.45 5.05.32L5.03.3l.02.01z"}))},label:o.createElement(D.A,{id:"theme.admonition.danger",description:"The default label used for the Danger admonition (:::danger)"},"danger")},info:{infimaClassName:"info",iconComponent:function(){return o.createElement("svg",{viewBox:"0 0 14 16"},o.createElement("path",{fillRule:"evenodd",d:"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"}))},label:o.createElement(D.A,{id:"theme.admonition.info",description:"The default label used for the Info admonition (:::info)"},"info")},caution:{infimaClassName:"warning",iconComponent:function(){return o.createElement("svg",{viewBox:"0 0 16 16"},o.createElement("path",{fillRule:"evenodd",d:"M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"}))},label:o.createElement(D.A,{id:"theme.admonition.caution",description:"The default label used for the Caution admonition (:::caution)"},"caution")}},fe={secondary:"note",important:"info",success:"tip",warning:"danger"};function ge(e){const{mdxAdmonitionTitle:t,rest:n}=function(e){const t=o.Children.toArray(e),n=t.find((e=>o.isValidElement(e)&&"mdxAdmonitionTitle"===e.props?.mdxType)),a=o.createElement(o.Fragment,null,t.filter((e=>e!==n)));return{mdxAdmonitionTitle:n,rest:a}}(e.children);return{...e,title:e.title??t,children:n}}const he={head:function(e){const t=o.Children.map(e.children,(e=>o.isValidElement(e)?function(e){if(e.props?.mdxType&&e.props.originalType){const{mdxType:t,originalType:n,...a}=e.props;return o.createElement(e.props.originalType,a)}return e}(e):e));return o.createElement(c.A,e,t)},code:function(e){const t=["a","abbr","b","br","button","cite","code","del","dfn","em","i","img","input","ins","kbd","label","object","output","q","ruby","s","small","span","strong","sub","sup","time","u","var","wbr"];return o.Children.toArray(e.children).every((e=>"string"==typeof e&&!e.includes("\n")||(0,o.isValidElement)(e)&&t.includes(e.props?.mdxType)))?o.createElement("code",e):o.createElement(Y,e)},a:function(e){return o.createElement(Z.A,e)},pre:function(e){return o.createElement(Y,(0,o.isValidElement)(e.children)&&"code"===e.children.props?.originalType?e.children.props:{...e})},details:function(e){const t=o.Children.toArray(e.children),n=t.find((e=>o.isValidElement(e)&&"summary"===e.props?.mdxType)),a=o.createElement(o.Fragment,null,t.filter((e=>e!==n)));return o.createElement(oe,(0,r.A)({},e,{summary:n}),a)},ul:function(e){return o.createElement("ul",(0,r.A)({},e,{className:le(e.className)}))},img:function(e){return o.createElement("img",(0,r.A)({loading:"lazy"},e,{className:(t=e.className,(0,i.A)(t,ie.img))}));var t},h1:e=>o.createElement(re,(0,r.A)({as:"h1"},e)),h2:e=>o.createElement(re,(0,r.A)({as:"h2"},e)),h3:e=>o.createElement(re,(0,r.A)({as:"h3"},e)),h4:e=>o.createElement(re,(0,r.A)({as:"h4"},e)),h5:e=>o.createElement(re,(0,r.A)({as:"h5"},e)),h6:e=>o.createElement(re,(0,r.A)({as:"h6"},e)),admonition:function(e){const{children:t,type:n,title:a,icon:r}=ge(e),c=function(e){const t=fe[e]??e,n=pe[t];return n||(console.warn(`No admonition config found for admonition type "${t}". Using Info as fallback.`),pe.info)}(n),l=a??c.label,{iconComponent:s}=c,u=r??o.createElement(s,null);return o.createElement("div",{className:(0,i.A)(d.G.common.admonition,d.G.common.admonitionType(e.type),"alert",`alert--${c.infimaClassName}`,se)},o.createElement("div",{className:ue},o.createElement("span",{className:me},u),l),o.createElement("div",{className:de},t))},mermaid:n(418).A};function ye(e){let{children:t}=e;return o.createElement(a.xA,{components:he},t)}},9022:(e,t,n)=>{"use strict";n.d(t,{A:()=>c});var o=n(6540),a=n(53),r=n(5489);function c(e){const{permalink:t,title:n,subLabel:c,isNext:l}=e;return o.createElement(r.A,{className:(0,a.A)("pagination-nav__link",l?"pagination-nav__link--next":"pagination-nav__link--prev"),to:t},c&&o.createElement("div",{className:"pagination-nav__sublabel"},c),o.createElement("div",{className:"pagination-nav__label"},n))}},6133:(e,t,n)=>{"use strict";n.d(t,{A:()=>l});var o=n(6540),a=n(53),r=n(5489);const c={tag:"tag_zVej",tagRegular:"tagRegular_sFm0",tagWithCount:"tagWithCount_h2kH"};function l(e){let{permalink:t,label:n,count:l}=e;return o.createElement(r.A,{href:t,className:(0,a.A)(c.tag,l?c.tagWithCount:c.tagRegular)},n,l&&o.createElement("span",null,l))}},2053:(e,t,n)=>{"use strict";n.d(t,{A:()=>i});var o=n(6540),a=n(53),r=n(1312),c=n(6133);const l={tags:"tags_jXut",tag:"tag_QGVx"};function i(e){let{tags:t}=e;return o.createElement(o.Fragment,null,o.createElement("b",null,o.createElement(r.A,{id:"theme.tags.tagsListLabel",description:"The label alongside a tag list"},"Tags:")),o.createElement("ul",{className:(0,a.A)(l.tags,"padding--none","margin-left--sm")},t.map((e=>{let{label:t,permalink:n}=e;return o.createElement("li",{key:n,className:l.tag},o.createElement(c.A,{label:t,permalink:n}))}))))}},8426:(e,t)=>{function n(e){let t,n=[];for(let o of e.split(",").map((e=>e.trim())))if(/^-?\d+$/.test(o))n.push(parseInt(o,10));else if(t=o.match(/^(-?\d+)(-|\.\.\.?|\u2025|\u2026|\u22EF)(-?\d+)$/)){let[e,o,a,r]=t;if(o&&r){o=parseInt(o),r=parseInt(r);const e=o<r?1:-1;"-"!==a&&".."!==a&&"\u2025"!==a||(r+=e);for(let t=o;t!==r;t+=e)n.push(t)}}return n}t.default=n,e.exports=n}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/89196f72.edb5fbb7.js b/docs/0.16.0/assets/js/89196f72.edb5fbb7.js new file mode 100644 index 00000000..a77c45ac --- /dev/null +++ b/docs/0.16.0/assets/js/89196f72.edb5fbb7.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[6995],{5680:(e,t,r)=>{r.d(t,{xA:()=>s,yg:()=>d});var n=r(6540);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?o(Object(r),!0).forEach((function(t){a(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):o(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function c(e,t){if(null==e)return{};var r,n,a=function(e,t){if(null==e)return{};var r,n,a={},o=Object.keys(e);for(n=0;n<o.length;n++)r=o[n],t.indexOf(r)>=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n<o.length;n++)r=o[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var l=n.createContext({}),u=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},s=function(e){var t=u(e.components);return n.createElement(l.Provider,{value:t},e.children)},p="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},f=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,l=e.parentName,s=c(e,["components","mdxType","originalType","parentName"]),p=u(r),f=a,d=p["".concat(l,".").concat(f)]||p[f]||m[f]||o;return r?n.createElement(d,i(i({ref:t},s),{},{components:r})):n.createElement(d,i({ref:t},s))}));function d(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,i=new Array(o);i[0]=f;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c[p]="string"==typeof e?e:a,i[1]=c;for(var u=2;u<o;u++)i[u]=r[u];return n.createElement.apply(null,i)}return n.createElement.apply(null,r)}f.displayName="MDXCreateElement"},4856:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>m,frontMatter:()=>o,metadata:()=>c,toc:()=>u});var n=r(8168),a=(r(6540),r(5680));const o={},i="Special Mathematical",c={unversionedId:"ast-builder/functions/math/special-mathematical",id:"ast-builder/functions/math/special-mathematical",title:"Special Mathematical",description:"Todo",source:"@site/docs/ast-builder/functions/math/special-mathematical.md",sourceDirName:"ast-builder/functions/math",slug:"/ast-builder/functions/math/special-mathematical",permalink:"/docs/0.16.0/ast-builder/functions/math/special-mathematical",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"Rounding",permalink:"/docs/0.16.0/ast-builder/functions/math/rounding"},next:{title:"Trigonometric",permalink:"/docs/0.16.0/ast-builder/functions/math/trigonometric"}},l={},u=[{value:"Todo",id:"todo",level:2}],s={toc:u},p="wrapper";function m(e){let{components:t,...r}=e;return(0,a.yg)(p,(0,n.A)({},s,r,{components:t,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"special-mathematical"},"Special Mathematical"),(0,a.yg)("h2",{id:"todo"},"Todo"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre"},"- PI: Returns the constant value of Pi.\n- RAND: Returns a random number.\n- SIGN: Returns the sign of a number.\n- SQRT: Returns the square root of a number.\n")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/89fc5f00.a011da22.js b/docs/0.16.0/assets/js/89fc5f00.a011da22.js new file mode 100644 index 00000000..36641b6f --- /dev/null +++ b/docs/0.16.0/assets/js/89fc5f00.a011da22.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[4646],{5680:(e,t,n)=>{n.d(t,{xA:()=>s,yg:()=>y});var r=n(6540);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function c(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?a(Object(n),!0).forEach((function(t){o(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):a(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function i(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},a=Object.keys(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var l=r.createContext({}),u=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):c(c({},t),e)),n},s=function(e){var t=u(e.components);return r.createElement(l.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},f=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,s=i(e,["components","mdxType","originalType","parentName"]),p=u(n),f=o,y=p["".concat(l,".").concat(f)]||p[f]||d[f]||a;return n?r.createElement(y,c(c({ref:t},s),{},{components:n})):r.createElement(y,c({ref:t},s))}));function y(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,c=new Array(a);c[0]=f;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i[p]="string"==typeof e?e:o,c[1]=i;for(var u=2;u<a;u++)c[u]=n[u];return r.createElement.apply(null,c)}return r.createElement.apply(null,n)}f.displayName="MDXCreateElement"},5559:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>c,default:()=>d,frontMatter:()=>a,metadata:()=>i,toc:()=>u});var r=n(8168),o=(n(6540),n(5680));const a={},c="Distance Calculation",i={unversionedId:"ast-builder/functions/geometry/distance-calculation",id:"ast-builder/functions/geometry/distance-calculation",title:"Distance Calculation",description:"Todo",source:"@site/docs/ast-builder/functions/geometry/distance-calculation.md",sourceDirName:"ast-builder/functions/geometry",slug:"/ast-builder/functions/geometry/distance-calculation",permalink:"/docs/0.16.0/ast-builder/functions/geometry/distance-calculation",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"Coordinate Extraction",permalink:"/docs/0.16.0/ast-builder/functions/geometry/coordinate-extraction"},next:{title:"Point Creation",permalink:"/docs/0.16.0/ast-builder/functions/geometry/point-creation"}},l={},u=[{value:"Todo",id:"todo",level:2}],s={toc:u},p="wrapper";function d(e){let{components:t,...n}=e;return(0,o.yg)(p,(0,r.A)({},s,n,{components:t,mdxType:"MDXLayout"}),(0,o.yg)("h1",{id:"distance-calculation"},"Distance Calculation"),(0,o.yg)("h2",{id:"todo"},"Todo"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre"},"- CALC_DISTANCE: Calculates the distance between two points.\n")))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/8be9dc67.6449ddb1.js b/docs/0.16.0/assets/js/8be9dc67.6449ddb1.js new file mode 100644 index 00000000..1ae3f653 --- /dev/null +++ b/docs/0.16.0/assets/js/8be9dc67.6449ddb1.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[5773],{5680:(e,n,t)=>{t.d(n,{xA:()=>d,yg:()=>y});var a=t(6540);function l(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function r(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function i(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?r(Object(t),!0).forEach((function(n){l(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):r(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function o(e,n){if(null==e)return{};var t,a,l=function(e,n){if(null==e)return{};var t,a,l={},r=Object.keys(e);for(a=0;a<r.length;a++)t=r[a],n.indexOf(t)>=0||(l[t]=e[t]);return l}(e,n);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a<r.length;a++)t=r[a],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(l[t]=e[t])}return l}var u=a.createContext({}),p=function(e){var n=a.useContext(u),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},d=function(e){var n=p(e.components);return a.createElement(u.Provider,{value:n},e.children)},g="mdxType",m={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},s=a.forwardRef((function(e,n){var t=e.components,l=e.mdxType,r=e.originalType,u=e.parentName,d=o(e,["components","mdxType","originalType","parentName"]),g=p(t),s=l,y=g["".concat(u,".").concat(s)]||g[s]||m[s]||r;return t?a.createElement(y,i(i({ref:n},d),{},{components:t})):a.createElement(y,i({ref:n},d))}));function y(e,n){var t=arguments,l=n&&n.mdxType;if("string"==typeof e||l){var r=t.length,i=new Array(r);i[0]=s;var o={};for(var u in n)hasOwnProperty.call(n,u)&&(o[u]=n[u]);o.originalType=e,o[g]="string"==typeof e?e:l,i[1]=o;for(var p=2;p<r;p++)i[p]=t[p];return a.createElement.apply(null,i)}return a.createElement.apply(null,t)}s.displayName="MDXCreateElement"},8882:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>u,contentTitle:()=>i,default:()=>m,frontMatter:()=>r,metadata:()=>o,toc:()=>p});var a=t(8168),l=(t(6540),t(5680));const r={sidebar_position:2},i="UPDATE",o={unversionedId:"sql-syntax/statements/data-manipulation/update",id:"sql-syntax/statements/data-manipulation/update",title:"UPDATE",description:"The UPDATE statement is used to modify existing records in a table. You can update one or more columns with new values, or even use subqueries to update values based on other tables.",source:"@site/docs/sql-syntax/statements/data-manipulation/update.md",sourceDirName:"sql-syntax/statements/data-manipulation",slug:"/sql-syntax/statements/data-manipulation/update",permalink:"/docs/0.16.0/sql-syntax/statements/data-manipulation/update",draft:!1,tags:[],version:"current",sidebarPosition:2,frontMatter:{sidebar_position:2},sidebar:"autoSidebar",previous:{title:"INSERT",permalink:"/docs/0.16.0/sql-syntax/statements/data-manipulation/insert"},next:{title:"DELETE",permalink:"/docs/0.16.0/sql-syntax/statements/data-manipulation/delete"}},u={},p=[{value:"Basic UPDATE Syntax",id:"basic-update-syntax",level:2},{value:"Examples",id:"examples",level:2},{value:"Updating a Single Column",id:"updating-a-single-column",level:3},{value:"Updating with a Condition",id:"updating-with-a-condition",level:3},{value:"Updating with a Subquery",id:"updating-with-a-subquery",level:3},{value:"Updating Based on the Result of Another Query",id:"updating-based-on-the-result-of-another-query",level:3},{value:"Not Supported Features",id:"not-supported-features",level:2}],d={toc:p},g="wrapper";function m(e){let{components:n,...t}=e;return(0,l.yg)(g,(0,a.A)({},d,t,{components:n,mdxType:"MDXLayout"}),(0,l.yg)("h1",{id:"update"},"UPDATE"),(0,l.yg)("p",null,"The ",(0,l.yg)("inlineCode",{parentName:"p"},"UPDATE")," statement is used to modify existing records in a table. You can update one or more columns with new values, or even use subqueries to update values based on other tables."),(0,l.yg)("h2",{id:"basic-update-syntax"},"Basic UPDATE Syntax"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"UPDATE table_name\nSET column1 = value1, column2 = value2, ...\nWHERE condition;\n")),(0,l.yg)("h2",{id:"examples"},"Examples"),(0,l.yg)("h3",{id:"updating-a-single-column"},"Updating a Single Column"),(0,l.yg)("p",null,"Consider the following ",(0,l.yg)("inlineCode",{parentName:"p"},"TableA"),":"),(0,l.yg)("table",null,(0,l.yg)("thead",{parentName:"table"},(0,l.yg)("tr",{parentName:"thead"},(0,l.yg)("th",{parentName:"tr",align:null},"id"),(0,l.yg)("th",{parentName:"tr",align:null},"num"),(0,l.yg)("th",{parentName:"tr",align:null},"num2"),(0,l.yg)("th",{parentName:"tr",align:null},"name"))),(0,l.yg)("tbody",{parentName:"table"},(0,l.yg)("tr",{parentName:"tbody"},(0,l.yg)("td",{parentName:"tr",align:null},"1"),(0,l.yg)("td",{parentName:"tr",align:null},"2"),(0,l.yg)("td",{parentName:"tr",align:null},"4"),(0,l.yg)("td",{parentName:"tr",align:null},"Hello")),(0,l.yg)("tr",{parentName:"tbody"},(0,l.yg)("td",{parentName:"tr",align:null},"1"),(0,l.yg)("td",{parentName:"tr",align:null},"9"),(0,l.yg)("td",{parentName:"tr",align:null},"5"),(0,l.yg)("td",{parentName:"tr",align:null},"World")),(0,l.yg)("tr",{parentName:"tbody"},(0,l.yg)("td",{parentName:"tr",align:null},"3"),(0,l.yg)("td",{parentName:"tr",align:null},"4"),(0,l.yg)("td",{parentName:"tr",align:null},"7"),(0,l.yg)("td",{parentName:"tr",align:null},"Great")),(0,l.yg)("tr",{parentName:"tbody"},(0,l.yg)("td",{parentName:"tr",align:null},"4"),(0,l.yg)("td",{parentName:"tr",align:null},"7"),(0,l.yg)("td",{parentName:"tr",align:null},"10"),(0,l.yg)("td",{parentName:"tr",align:null},"Job")))),(0,l.yg)("p",null,"To update the ",(0,l.yg)("inlineCode",{parentName:"p"},"id")," column for all rows in ",(0,l.yg)("inlineCode",{parentName:"p"},"TableA"),", you can use the following query:"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"UPDATE TableA SET id = 2;\n")),(0,l.yg)("p",null,"The resulting ",(0,l.yg)("inlineCode",{parentName:"p"},"TableA")," would look like this:"),(0,l.yg)("table",null,(0,l.yg)("thead",{parentName:"table"},(0,l.yg)("tr",{parentName:"thead"},(0,l.yg)("th",{parentName:"tr",align:null},"id"),(0,l.yg)("th",{parentName:"tr",align:null},"num"),(0,l.yg)("th",{parentName:"tr",align:null},"num2"),(0,l.yg)("th",{parentName:"tr",align:null},"name"))),(0,l.yg)("tbody",{parentName:"table"},(0,l.yg)("tr",{parentName:"tbody"},(0,l.yg)("td",{parentName:"tr",align:null},"2"),(0,l.yg)("td",{parentName:"tr",align:null},"2"),(0,l.yg)("td",{parentName:"tr",align:null},"4"),(0,l.yg)("td",{parentName:"tr",align:null},"Hello")),(0,l.yg)("tr",{parentName:"tbody"},(0,l.yg)("td",{parentName:"tr",align:null},"2"),(0,l.yg)("td",{parentName:"tr",align:null},"9"),(0,l.yg)("td",{parentName:"tr",align:null},"5"),(0,l.yg)("td",{parentName:"tr",align:null},"World")),(0,l.yg)("tr",{parentName:"tbody"},(0,l.yg)("td",{parentName:"tr",align:null},"2"),(0,l.yg)("td",{parentName:"tr",align:null},"4"),(0,l.yg)("td",{parentName:"tr",align:null},"7"),(0,l.yg)("td",{parentName:"tr",align:null},"Great")),(0,l.yg)("tr",{parentName:"tbody"},(0,l.yg)("td",{parentName:"tr",align:null},"2"),(0,l.yg)("td",{parentName:"tr",align:null},"7"),(0,l.yg)("td",{parentName:"tr",align:null},"10"),(0,l.yg)("td",{parentName:"tr",align:null},"Job")))),(0,l.yg)("h3",{id:"updating-with-a-condition"},"Updating with a Condition"),(0,l.yg)("p",null,"If you want to update only specific rows that meet a certain condition, you can use the ",(0,l.yg)("inlineCode",{parentName:"p"},"WHERE")," clause. For example, to update the ",(0,l.yg)("inlineCode",{parentName:"p"},"id")," column only for the row with ",(0,l.yg)("inlineCode",{parentName:"p"},"num = 9"),":"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"UPDATE TableA SET id = 4 WHERE num = 9;\n")),(0,l.yg)("h3",{id:"updating-with-a-subquery"},"Updating with a Subquery"),(0,l.yg)("p",null,"You can also use a subquery in the ",(0,l.yg)("inlineCode",{parentName:"p"},"UPDATE")," statement to update a column based on other table's values. For example, to update the ",(0,l.yg)("inlineCode",{parentName:"p"},"num2")," column in ",(0,l.yg)("inlineCode",{parentName:"p"},"TableA")," with the ",(0,l.yg)("inlineCode",{parentName:"p"},"rank")," column value from ",(0,l.yg)("inlineCode",{parentName:"p"},"TableB")," where the ",(0,l.yg)("inlineCode",{parentName:"p"},"num")," column values match, and the ",(0,l.yg)("inlineCode",{parentName:"p"},"num = 7"),":"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"UPDATE TableA SET num2 = (SELECT rank FROM TableB WHERE num = TableA.num) WHERE num = 7;\n")),(0,l.yg)("h3",{id:"updating-based-on-the-result-of-another-query"},"Updating Based on the Result of Another Query"),(0,l.yg)("p",null,"You can update a column based on the result of another query. For example, to update the ",(0,l.yg)("inlineCode",{parentName:"p"},"num2")," column in ",(0,l.yg)("inlineCode",{parentName:"p"},"TableA")," with the ",(0,l.yg)("inlineCode",{parentName:"p"},"rank")," column value from ",(0,l.yg)("inlineCode",{parentName:"p"},"TableB")," where the ",(0,l.yg)("inlineCode",{parentName:"p"},"num")," column values match, and the ",(0,l.yg)("inlineCode",{parentName:"p"},"num")," is the minimum ",(0,l.yg)("inlineCode",{parentName:"p"},"num")," in ",(0,l.yg)("inlineCode",{parentName:"p"},"TableA"),":"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"UPDATE TableA SET num2 = (SELECT rank FROM TableB WHERE num = TableA.num) WHERE num = (SELECT MIN(num) FROM TableA);\n")),(0,l.yg)("h2",{id:"not-supported-features"},"Not Supported Features"),(0,l.yg)("ul",null,(0,l.yg)("li",{parentName:"ul"},"Using ",(0,l.yg)("inlineCode",{parentName:"li"},"JOIN")," in an ",(0,l.yg)("inlineCode",{parentName:"li"},"UPDATE")," statement is not supported."),(0,l.yg)("li",{parentName:"ul"},"Updating a table using compound identifiers (e.g., ",(0,l.yg)("inlineCode",{parentName:"li"},"ErrTestTable.id = 1"),") is not supported."),(0,l.yg)("li",{parentName:"ul"},"Updating a non-existent table will result in a ",(0,l.yg)("inlineCode",{parentName:"li"},"TableNotFound")," error."),(0,l.yg)("li",{parentName:"ul"},"Updating a non-existent column will result in a ",(0,l.yg)("inlineCode",{parentName:"li"},"ColumnNotFound")," error.")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/8c7569e5.4214ccc3.js b/docs/0.16.0/assets/js/8c7569e5.4214ccc3.js new file mode 100644 index 00000000..d7e62fb4 --- /dev/null +++ b/docs/0.16.0/assets/js/8c7569e5.4214ccc3.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[6205],{5680:(e,t,n)=>{n.d(t,{xA:()=>s,yg:()=>f});var r=n(6540);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function c(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},o=Object.keys(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var u=r.createContext({}),l=function(e){var t=r.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},s=function(e){var t=l(e.components);return r.createElement(u.Provider,{value:t},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,u=e.parentName,s=c(e,["components","mdxType","originalType","parentName"]),d=l(n),m=a,f=d["".concat(u,".").concat(m)]||d[m]||p[m]||o;return n?r.createElement(f,i(i({ref:t},s),{},{components:n})):r.createElement(f,i({ref:t},s))}));function f(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=m;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c[d]="string"==typeof e?e:a,i[1]=c;for(var l=2;l<o;l++)i[l]=n[l];return r.createElement.apply(null,i)}return r.createElement.apply(null,n)}m.displayName="MDXCreateElement"},2715:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>u,contentTitle:()=>i,default:()=>p,frontMatter:()=>o,metadata:()=>c,toc:()=>l});var r=n(8168),a=(n(6540),n(5680));const o={},i="Current Date and Time",c={unversionedId:"ast-builder/functions/date-&-time/current-date-and-time",id:"ast-builder/functions/date-&-time/current-date-and-time",title:"Current Date and Time",description:"GlueSQL provides a function to get the current date and time: now.",source:"@site/docs/ast-builder/functions/date-&-time/current-date-and-time.md",sourceDirName:"ast-builder/functions/date-&-time",slug:"/ast-builder/functions/date-&-time/current-date-and-time",permalink:"/docs/0.16.0/ast-builder/functions/date-&-time/current-date-and-time",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"Conversion",permalink:"/docs/0.16.0/ast-builder/functions/date-&-time/conversion"},next:{title:"Date and Time Extraction",permalink:"/docs/0.16.0/ast-builder/functions/date-&-time/date-and-time-extraction"}},u={},l=[{value:"Now - now",id:"now---now",level:2}],s={toc:l},d="wrapper";function p(e){let{components:t,...n}=e;return(0,a.yg)(d,(0,r.A)({},s,n,{components:t,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"current-date-and-time"},"Current Date and Time"),(0,a.yg)("p",null,"GlueSQL provides a function to get the current date and time: ",(0,a.yg)("inlineCode",{parentName:"p"},"now"),"."),(0,a.yg)("h2",{id:"now---now"},"Now - now"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"now")," function returns the current date and time."),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Record")\n .select()\n .filter(col("time_stamp").gt(now())) // select rows where "time_stamp" is later than current time\n .project("id, time_stamp")\n .execute(glue)\n .await;\n')),(0,a.yg)("p",null,"In the above example, the ",(0,a.yg)("inlineCode",{parentName:"p"},"filter")," method uses ",(0,a.yg)("inlineCode",{parentName:"p"},"now"),' to select rows where the "time_stamp" column is later than the current time.'),(0,a.yg)("p",null,"When inserting data into a table, you can use the ",(0,a.yg)("inlineCode",{parentName:"p"},"now")," function to record the current time:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Record")\n .insert()\n .values(vec![\n "1, \'2022-12-23T05:30:11.164932863\'",\n "2, NOW()", // Inserts the current time\n "3, \'9999-12-31T23:59:40.364832862\'",\n ])\n .execute(glue)\n .await;\n')),(0,a.yg)("p",null,'In the example above, the "time_stamp" column for the row with id 2 is set to the current time at the moment of insertion.'))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/8cf2dd9c.d59af323.js b/docs/0.16.0/assets/js/8cf2dd9c.d59af323.js new file mode 100644 index 00000000..65e5ecda --- /dev/null +++ b/docs/0.16.0/assets/js/8cf2dd9c.d59af323.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[2636],{5680:(e,n,t)=>{t.d(n,{xA:()=>u,yg:()=>h});var r=t(6540);function a(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function l(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function i(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?l(Object(t),!0).forEach((function(n){a(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):l(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function o(e,n){if(null==e)return{};var t,r,a=function(e,n){if(null==e)return{};var t,r,a={},l=Object.keys(e);for(r=0;r<l.length;r++)t=l[r],n.indexOf(t)>=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(r=0;r<l.length;r++)t=l[r],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var s=r.createContext({}),c=function(e){var n=r.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},u=function(e){var n=c(e.components);return r.createElement(s.Provider,{value:n},e.children)},p="mdxType",y={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},g=r.forwardRef((function(e,n){var t=e.components,a=e.mdxType,l=e.originalType,s=e.parentName,u=o(e,["components","mdxType","originalType","parentName"]),p=c(t),g=a,h=p["".concat(s,".").concat(g)]||p[g]||y[g]||l;return t?r.createElement(h,i(i({ref:n},u),{},{components:t})):r.createElement(h,i({ref:n},u))}));function h(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var l=t.length,i=new Array(l);i[0]=g;var o={};for(var s in n)hasOwnProperty.call(n,s)&&(o[s]=n[s]);o.originalType=e,o[p]="string"==typeof e?e:a,i[1]=o;for(var c=2;c<l;c++)i[c]=t[c];return r.createElement.apply(null,i)}return r.createElement.apply(null,t)}g.displayName="MDXCreateElement"},978:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>s,contentTitle:()=>i,default:()=>y,frontMatter:()=>l,metadata:()=>o,toc:()=>c});var r=t(8168),a=(t(6540),t(5680));const l={},i="CHR",o={unversionedId:"sql-syntax/functions/text/chr",id:"sql-syntax/functions/text/chr",title:"CHR",description:"The CHR function in SQL returns the character represented by the specified ASCII value.",source:"@site/docs/sql-syntax/functions/text/chr.md",sourceDirName:"sql-syntax/functions/text",slug:"/sql-syntax/functions/text/chr",permalink:"/docs/0.16.0/sql-syntax/functions/text/chr",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"ASCII",permalink:"/docs/0.16.0/sql-syntax/functions/text/ascii"},next:{title:"CONCAT_WS",permalink:"/docs/0.16.0/sql-syntax/functions/text/concat-ws"}},s={},c=[{value:"Syntax",id:"syntax",level:2},{value:"Parameters",id:"parameters",level:2},{value:"Examples",id:"examples",level:2}],u={toc:c},p="wrapper";function y(e){let{components:n,...t}=e;return(0,a.yg)(p,(0,r.A)({},u,t,{components:n,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"chr"},"CHR"),(0,a.yg)("p",null,"The CHR function in SQL returns the character represented by the specified ASCII value."),(0,a.yg)("h2",{id:"syntax"},"Syntax"),(0,a.yg)("p",null,"The syntax for the CHR function in SQL is:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"CHR ( ascii_value )\n")),(0,a.yg)("h2",{id:"parameters"},"Parameters"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"ascii_value"),": This is the ASCII value for which the character should be returned. It should be an integer value between 0 and 255.")),(0,a.yg)("h2",{id:"examples"},"Examples"),(0,a.yg)("p",null,"Let's consider a few examples to understand how to use the CHR function."),(0,a.yg)("p",null,"To get the character for an ASCII value:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"VALUES(CHR(70));\n")),(0,a.yg)("p",null,"This will return ",(0,a.yg)("inlineCode",{parentName:"p"},"'F'"),", which is the character for the ASCII value 70."),(0,a.yg)("p",null,"Please note that the CHR function expects an integer value between 0 and 255. If a value outside this range is passed, it will throw an error. For instance:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"VALUES(CHR(7070));\n")),(0,a.yg)("p",null,"This will throw an error because 7070 is not a valid ASCII value."),(0,a.yg)("p",null,"You can also use the CHR function in a SELECT statement. Consider the following table named 'Chr':"),(0,a.yg)("table",null,(0,a.yg)("thead",{parentName:"table"},(0,a.yg)("tr",{parentName:"thead"},(0,a.yg)("th",{parentName:"tr",align:null},"id"),(0,a.yg)("th",{parentName:"tr",align:null},"num"))),(0,a.yg)("tbody",{parentName:"table"},(0,a.yg)("tr",{parentName:"tbody"},(0,a.yg)("td",{parentName:"tr",align:null},"1"),(0,a.yg)("td",{parentName:"tr",align:null},"70")))),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE Chr (\n id INTEGER,\n num INTEGER\n);\nINSERT INTO Chr VALUES (1, 70);\n")),(0,a.yg)("p",null,"You can select the character for the 'num' column:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT CHR(num) AS chr FROM Chr;\n")),(0,a.yg)("p",null,"This will return ",(0,a.yg)("inlineCode",{parentName:"p"},"'F'"),", which is the character for the ASCII value 70."),(0,a.yg)("p",null,"The CHR function can also take an integer value directly:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT CHR(65) AS chr FROM Chr;\n")),(0,a.yg)("p",null,"This will return ",(0,a.yg)("inlineCode",{parentName:"p"},"'A'"),", which is the character for the ASCII value 65."),(0,a.yg)("p",null,"If a non-integer value is passed to the function, it will throw an error. For instance:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT CHR('ukjhg') AS chr FROM Chr;\n")),(0,a.yg)("p",null,"This will throw an error because 'ukjhg' is not an integer value."),(0,a.yg)("p",null,"Remember, the CHR function expects an integer value between 0 and 255. If the column value is outside this range, it will throw an error:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO Chr VALUES (1, 4345);\nSELECT CHR(num) AS chr FROM Chr;\n")),(0,a.yg)("p",null,"This will throw an error because 4345 is not a valid ASCII value."))}y.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/8d6e802b.dffe0fdb.js b/docs/0.16.0/assets/js/8d6e802b.dffe0fdb.js new file mode 100644 index 00000000..e58bd75c --- /dev/null +++ b/docs/0.16.0/assets/js/8d6e802b.dffe0fdb.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[2468],{5680:(e,t,n)=>{n.d(t,{xA:()=>g,yg:()=>m});var r=n(6540);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function s(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?a(Object(n),!0).forEach((function(t){o(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):a(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},a=Object.keys(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var i=r.createContext({}),u=function(e){var t=r.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},g=function(e){var t=u(e.components);return r.createElement(i.Provider,{value:t},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},p=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,i=e.parentName,g=l(e,["components","mdxType","originalType","parentName"]),d=u(n),p=o,m=d["".concat(i,".").concat(p)]||d[p]||c[p]||a;return n?r.createElement(m,s(s({ref:t},g),{},{components:n})):r.createElement(m,s({ref:t},g))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,s=new Array(a);s[0]=p;var l={};for(var i in t)hasOwnProperty.call(t,i)&&(l[i]=t[i]);l.originalType=e,l[d]="string"==typeof e?e:o,s[1]=l;for(var u=2;u<a;u++)s[u]=n[u];return r.createElement.apply(null,s)}return r.createElement.apply(null,n)}p.displayName="MDXCreateElement"},4515:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>i,contentTitle:()=>s,default:()=>c,frontMatter:()=>a,metadata:()=>l,toc:()=>u});var r=n(8168),o=(n(6540),n(5680));const a={},s="Sled Storage",l={unversionedId:"storages/supported-storages/sled-storage",id:"storages/supported-storages/sled-storage",title:"Sled Storage",description:"SledStorage is currently the representative persistent data storage for GlueSQL. As the name suggests, it's a storage option based on the Sled key-value embedded database built in Rust (Sled on Github).",source:"@site/docs/storages/supported-storages/sled-storage.md",sourceDirName:"storages/supported-storages",slug:"/storages/supported-storages/sled-storage",permalink:"/docs/0.16.0/storages/supported-storages/sled-storage",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"Shared Memory Storage",permalink:"/docs/0.16.0/storages/supported-storages/shared-memory-storage"},next:{title:"WebStorage (local & session)",permalink:"/docs/0.16.0/storages/supported-storages/web-storage"}},i={},u=[{value:"How to use",id:"how-to-use",level:2},{value:"Things to Know About Transactions",id:"things-to-know-about-transactions",level:2},{value:"Summary",id:"summary",level:2}],g={toc:u},d="wrapper";function c(e){let{components:t,...n}=e;return(0,o.yg)(d,(0,r.A)({},g,n,{components:t,mdxType:"MDXLayout"}),(0,o.yg)("h1",{id:"sled-storage"},"Sled Storage"),(0,o.yg)("p",null,"SledStorage is currently the representative persistent data storage for GlueSQL. As the name suggests, it's a storage option based on the Sled key-value embedded database built in Rust (",(0,o.yg)("a",{parentName:"p",href:"https://github.com/spacejam/sled"},"Sled on Github"),")."),(0,o.yg)("p",null,"SledStorage can only be used in a Rust environment. It is the only storage among those currently supported by GlueSQL that implements all Store traits, from non-clustered indexes to transactions. If you're looking for a basic storage to handle and store data in a Rust environment, SledStorage is an excellent choice."),(0,o.yg)("h2",{id:"how-to-use"},"How to use"),(0,o.yg)("p",null,"You can simply create a SledStorage instance using a path, as shown below:"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-rust"},'use {\n gluesql::{prelude::Glue, sled_storage::SledStorage},\n sled_storage::sled,\n std::convert::TryFrom,\n};\n\nfn main() {\n let storage = SledStorage::new("data/temp").unwrap();\n let mut glue = Glue::new(storage);\n\n let sqls = "\n CREATE TABLE Glue (id INTEGER);\n INSERT INTO Glue VALUES (100), (200);\n ";\n\n glue.execute(sqls).unwrap();\n}\n')),(0,o.yg)("p",null,"If you want to use the Sled that SledStorage uses directly with a specific configuration, you can do so as follows:"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-rust"},'let config = sled::Config::default()\n .path("data/using_config")\n .temporary(true)\n .mode(sled::Mode::HighThroughput);\n\nlet storage = SledStorage::try_from(config).unwrap();\nlet mut glue = Glue::new(storage);\n')),(0,o.yg)("h2",{id:"things-to-know-about-transactions"},"Things to Know About Transactions"),(0,o.yg)("p",null,"The implementation of transactions in SledStorage manages not only data but also indexes and schema information based on snapshots. For example, if you use the following commands:"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-sql"},"BEGIN;\n\nCREATE TABLE Foo;\nINSERT INTO Foo VALUES (1);\n\nROLLBACK;\n")),(0,o.yg)("p",null,"The above usage will result in a rollback of even the contents regarding the Foo table. The transaction isolation level is repeatable read (snapshot isolation)."),(0,o.yg)("p",null,"By default, there is a timeout for Transactions. The default is set to one hour, but you can modify the value or remove the timeout if desired."),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-rust"},"storage.set_transaction_timeout(Some(1000)); // 1 sec\nstorage.set_transaction_timeout(None); // no timeout\n")),(0,o.yg)("h2",{id:"summary"},"Summary"),(0,o.yg)("p",null,"If you're looking for a storage to handle data for general purposes in a Rust environment, SledStorage would be your go-to choice. It offers all the necessary features of a database system, such as managing non-clustered indexes, handling transactions, and maintaining persistent storage. Additionally, its snapshot-based transaction model ensures consistency and reliability, making it an excellent choice for applications requiring persistent data storage."))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/920bdc78.764abce5.js b/docs/0.16.0/assets/js/920bdc78.764abce5.js new file mode 100644 index 00000000..11e9846f --- /dev/null +++ b/docs/0.16.0/assets/js/920bdc78.764abce5.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[666],{5680:(e,n,t)=>{t.d(n,{xA:()=>u,yg:()=>y});var r=t(6540);function i(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function o(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function a(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?o(Object(t),!0).forEach((function(n){i(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):o(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function l(e,n){if(null==e)return{};var t,r,i=function(e,n){if(null==e)return{};var t,r,i={},o=Object.keys(e);for(r=0;r<o.length;r++)t=o[r],n.indexOf(t)>=0||(i[t]=e[t]);return i}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r<o.length;r++)t=o[r],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(i[t]=e[t])}return i}var s=r.createContext({}),d=function(e){var n=r.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):a(a({},n),e)),t},u=function(e){var n=d(e.components);return r.createElement(s.Provider,{value:n},e.children)},c="mdxType",p={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},f=r.forwardRef((function(e,n){var t=e.components,i=e.mdxType,o=e.originalType,s=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),c=d(t),f=i,y=c["".concat(s,".").concat(f)]||c[f]||p[f]||o;return t?r.createElement(y,a(a({ref:n},u),{},{components:t})):r.createElement(y,a({ref:n},u))}));function y(e,n){var t=arguments,i=n&&n.mdxType;if("string"==typeof e||i){var o=t.length,a=new Array(o);a[0]=f;var l={};for(var s in n)hasOwnProperty.call(n,s)&&(l[s]=n[s]);l.originalType=e,l[c]="string"==typeof e?e:i,a[1]=l;for(var d=2;d<o;d++)a[d]=t[d];return r.createElement.apply(null,a)}return r.createElement.apply(null,t)}f.displayName="MDXCreateElement"},6307:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>s,contentTitle:()=>a,default:()=>p,frontMatter:()=>o,metadata:()=>l,toc:()=>d});var r=t(8168),i=(t(6540),t(5680));const o={},a="DIV",l={unversionedId:"sql-syntax/functions/math/div",id:"sql-syntax/functions/math/div",title:"DIV",description:"The DIV function is used to perform integer division. It takes two arguments (a dividend and a divisor) and returns the integer quotient of the division operation. Both dividend and divisor can be FLOAT or INTEGER type. The return type of the function is INTEGER.",source:"@site/docs/sql-syntax/functions/math/div.md",sourceDirName:"sql-syntax/functions/math",slug:"/sql-syntax/functions/math/div",permalink:"/docs/0.16.0/sql-syntax/functions/math/div",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"DEGREES",permalink:"/docs/0.16.0/sql-syntax/functions/math/degrees"},next:{title:"EXP",permalink:"/docs/0.16.0/sql-syntax/functions/math/exp"}},s={},d=[{value:"Example",id:"example",level:2},{value:"Errors",id:"errors",level:2}],u={toc:d},c="wrapper";function p(e){let{components:n,...t}=e;return(0,i.yg)(c,(0,r.A)({},u,t,{components:n,mdxType:"MDXLayout"}),(0,i.yg)("h1",{id:"div"},"DIV"),(0,i.yg)("p",null,"The ",(0,i.yg)("inlineCode",{parentName:"p"},"DIV")," function is used to perform integer division. It takes two arguments (a dividend and a divisor) and returns the integer quotient of the division operation. Both dividend and divisor can be FLOAT or INTEGER type. The return type of the function is INTEGER."),(0,i.yg)("h2",{id:"example"},"Example"),(0,i.yg)("p",null,"The following example demonstrates the usage of the ",(0,i.yg)("inlineCode",{parentName:"p"},"DIV")," function in a SQL query:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE FloatDiv (\n dividend FLOAT DEFAULT DIV(30, 11),\n divisor FLOAT DEFAULT DIV(3, 2)\n);\n\nINSERT INTO FloatDiv (dividend, divisor) VALUES (12.0, 3.0), (12.34, 56.78), (-12.3, 4.0);\n\nSELECT DIV(dividend, divisor) FROM FloatDiv;\n")),(0,i.yg)("p",null,"This will return the following result:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre"},"DIV(dividend, divisor)\n4\n0\n-4\n")),(0,i.yg)("h2",{id:"errors"},"Errors"),(0,i.yg)("ol",null,(0,i.yg)("li",{parentName:"ol"},"If the divisor is zero, a ",(0,i.yg)("inlineCode",{parentName:"li"},"DivisorShouldNotBeZero")," error will be raised."),(0,i.yg)("li",{parentName:"ol"},"If either of the arguments is not of FLOAT or INTEGER type, a ",(0,i.yg)("inlineCode",{parentName:"li"},"FunctionRequiresFloatOrIntegerValue")," error will be raised."),(0,i.yg)("li",{parentName:"ol"},"If the number of arguments provided to the function is not equal to 2, a ",(0,i.yg)("inlineCode",{parentName:"li"},"FunctionArgsLengthNotMatching")," error will be raised.")))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/928a5d6f.b84c0c0b.js b/docs/0.16.0/assets/js/928a5d6f.b84c0c0b.js new file mode 100644 index 00000000..8e56a054 --- /dev/null +++ b/docs/0.16.0/assets/js/928a5d6f.b84c0c0b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[6576],{5680:(e,t,n)=>{n.d(t,{xA:()=>d,yg:()=>f});var r=n(6540);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},i=Object.keys(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=r.createContext({}),c=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},d=function(e){var t=c(e.components);return r.createElement(l.Provider,{value:t},e.children)},u="mdxType",g={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},p=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,l=e.parentName,d=s(e,["components","mdxType","originalType","parentName"]),u=c(n),p=a,f=u["".concat(l,".").concat(p)]||u[p]||g[p]||i;return n?r.createElement(f,o(o({ref:t},d),{},{components:n})):r.createElement(f,o({ref:t},d))}));function f(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,o=new Array(i);o[0]=p;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[u]="string"==typeof e?e:a,o[1]=s;for(var c=2;c<i;c++)o[c]=n[c];return r.createElement.apply(null,o)}return r.createElement.apply(null,n)}p.displayName="MDXCreateElement"},7995:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>o,default:()=>g,frontMatter:()=>i,metadata:()=>s,toc:()=>c});var r=n(8168),a=(n(6540),n(5680));const i={},o="TO_DATE",s={unversionedId:"sql-syntax/functions/datetime/to-date",id:"sql-syntax/functions/datetime/to-date",title:"TO_DATE",description:"The TO_DATE function in SQL is used to convert a string into a DATE. This function takes two arguments, the string to be converted and a format string that specifies the format of the input string.",source:"@site/docs/sql-syntax/functions/datetime/to-date.md",sourceDirName:"sql-syntax/functions/datetime",slug:"/sql-syntax/functions/datetime/to-date",permalink:"/docs/0.16.0/sql-syntax/functions/datetime/to-date",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"NOW",permalink:"/docs/0.16.0/sql-syntax/functions/datetime/now"},next:{title:"TO_TIME",permalink:"/docs/0.16.0/sql-syntax/functions/datetime/to-time"}},l={},c=[{value:"Syntax",id:"syntax",level:2},{value:"Examples",id:"examples",level:2},{value:"Converting a string to a DATE",id:"converting-a-string-to-a-date",level:3},{value:"Converting a string to a DATE with a different format",id:"converting-a-string-to-a-date-with-a-different-format",level:3},{value:"Error Handling",id:"error-handling",level:2}],d={toc:c},u="wrapper";function g(e){let{components:t,...n}=e;return(0,a.yg)(u,(0,r.A)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"to_date"},"TO_DATE"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"TO_DATE")," function in SQL is used to convert a string into a DATE. This function takes two arguments, the string to be converted and a format string that specifies the format of the input string."),(0,a.yg)("h2",{id:"syntax"},"Syntax"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"TO_DATE(string, format)\n")),(0,a.yg)("h2",{id:"examples"},"Examples"),(0,a.yg)("h3",{id:"converting-a-string-to-a-date"},"Converting a string to a DATE"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"VALUES(TO_DATE('2017-06-15', '%Y-%m-%d'));\n")),(0,a.yg)("p",null,"In this example, the string '2017-06-15' is converted into a DATE using the format '%Y-%m-%d', where %Y is the four-digit year, %m is the two-digit month, and %d is the two-digit day."),(0,a.yg)("h3",{id:"converting-a-string-to-a-date-with-a-different-format"},"Converting a string to a DATE with a different format"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT TO_DATE('2017-jun-15','%Y-%b-%d') AS date;\n")),(0,a.yg)("p",null,"In this example, the string '2017-jun-15' is converted into a DATE using the format '%Y-%b-%d', where %Y is the four-digit year, %b is the abbreviated month name, and %d is the two-digit day."),(0,a.yg)("h2",{id:"error-handling"},"Error Handling"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"TO_DATE")," function requires a string value as its first argument. If a non-string value is provided, it will return an error."),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT TO_DATE(DATE '2017-06-15','%Y-%m-%d') AS date;\n")),(0,a.yg)("p",null,"In this case, the DATE '2017-06-15' is not a string and will cause an error."),(0,a.yg)("p",null,"Additionally, if the format string does not match the format of the input string, an error will also be returned. For example:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT TO_DATE('2015-09-05', '%Y-%m') AS date;\n")),(0,a.yg)("p",null,"In this case, the format string '%Y-%m' does not match the input string '2015-09-05', so an error will be returned."))}g.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/92dd0956.d500cc47.js b/docs/0.16.0/assets/js/92dd0956.d500cc47.js new file mode 100644 index 00000000..f433cc72 --- /dev/null +++ b/docs/0.16.0/assets/js/92dd0956.d500cc47.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[5086],{5680:(e,t,n)=>{n.d(t,{xA:()=>p,yg:()=>y});var a=n(6540);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?l(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):l(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,a,r=function(e,t){if(null==e)return{};var n,a,r={},l=Object.keys(e);for(a=0;a<l.length;a++)n=l[a],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a<l.length;a++)n=l[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var i=a.createContext({}),c=function(e){var t=a.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=c(e.components);return a.createElement(i.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,l=e.originalType,i=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=c(n),m=r,y=d["".concat(i,".").concat(m)]||d[m]||u[m]||l;return n?a.createElement(y,o(o({ref:t},p),{},{components:n})):a.createElement(y,o({ref:t},p))}));function y(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var l=n.length,o=new Array(l);o[0]=m;var s={};for(var i in t)hasOwnProperty.call(t,i)&&(s[i]=t[i]);s.originalType=e,s[d]="string"==typeof e?e:r,o[1]=s;for(var c=2;c<l;c++)o[c]=n[c];return a.createElement.apply(null,o)}return a.createElement.apply(null,n)}m.displayName="MDXCreateElement"},5480:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>i,contentTitle:()=>o,default:()=>u,frontMatter:()=>l,metadata:()=>s,toc:()=>c});var a=n(8168),r=(n(6540),n(5680));const l={sidebar_position:3},o="DELETE",s={unversionedId:"sql-syntax/statements/data-manipulation/delete",id:"sql-syntax/statements/data-manipulation/delete",title:"DELETE",description:"The DELETE statement is used to remove records from a table. You can delete a single row, multiple rows, or all rows at once based on specific conditions.",source:"@site/docs/sql-syntax/statements/data-manipulation/delete.md",sourceDirName:"sql-syntax/statements/data-manipulation",slug:"/sql-syntax/statements/data-manipulation/delete",permalink:"/docs/0.16.0/sql-syntax/statements/data-manipulation/delete",draft:!1,tags:[],version:"current",sidebarPosition:3,frontMatter:{sidebar_position:3},sidebar:"autoSidebar",previous:{title:"UPDATE",permalink:"/docs/0.16.0/sql-syntax/statements/data-manipulation/update"},next:{title:"Transaction",permalink:"/docs/0.16.0/sql-syntax/statements/transaction"}},i={},c=[{value:"Basic DELETE Syntax",id:"basic-delete-syntax",level:2},{value:"Examples",id:"examples",level:2},{value:"Deleting Records with a WHERE Clause",id:"deleting-records-with-a-where-clause",level:3},{value:"Deleting All Records",id:"deleting-all-records",level:3}],p={toc:c},d="wrapper";function u(e){let{components:t,...n}=e;return(0,r.yg)(d,(0,a.A)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,r.yg)("h1",{id:"delete"},"DELETE"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"DELETE")," statement is used to remove records from a table. You can delete a single row, multiple rows, or all rows at once based on specific conditions."),(0,r.yg)("h2",{id:"basic-delete-syntax"},"Basic DELETE Syntax"),(0,r.yg)("p",null,"To delete records from a table, use the following syntax:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"DELETE FROM table_name\nWHERE condition;\n")),(0,r.yg)("p",null,"If you want to delete all records from a table, you can omit the ",(0,r.yg)("inlineCode",{parentName:"p"},"WHERE")," clause:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"DELETE FROM table_name;\n")),(0,r.yg)("h2",{id:"examples"},"Examples"),(0,r.yg)("p",null,"Consider the following ",(0,r.yg)("inlineCode",{parentName:"p"},"Foo")," table:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE Foo (\n id INTEGER PRIMARY KEY,\n score INTEGER,\n flag BOOLEAN\n);\n")),(0,r.yg)("p",null,"With the following records:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO Foo VALUES\n (1, 100, TRUE),\n (2, 300, FALSE),\n (3, 700, TRUE);\n")),(0,r.yg)("h3",{id:"deleting-records-with-a-where-clause"},"Deleting Records with a WHERE Clause"),(0,r.yg)("p",null,"To delete records that meet a specific condition, use the ",(0,r.yg)("inlineCode",{parentName:"p"},"WHERE")," clause:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"DELETE FROM Foo WHERE flag = FALSE;\n")),(0,r.yg)("p",null,"After executing the above query, the remaining records in the ",(0,r.yg)("inlineCode",{parentName:"p"},"Foo")," table will be:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre"},"id | score | flag\n---+-------+------\n1 | 100 | true\n3 | 700 | true\n")),(0,r.yg)("h3",{id:"deleting-all-records"},"Deleting All Records"),(0,r.yg)("p",null,"To delete all records from a table, omit the ",(0,r.yg)("inlineCode",{parentName:"p"},"WHERE")," clause:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"DELETE FROM Foo;\n")),(0,r.yg)("p",null,"After executing the above query, the ",(0,r.yg)("inlineCode",{parentName:"p"},"Foo")," table will be empty:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre"},"id | score | flag\n(no rows)\n")))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/935f2afb.2f263db7.js b/docs/0.16.0/assets/js/935f2afb.2f263db7.js new file mode 100644 index 00000000..127e8e8e --- /dev/null +++ b/docs/0.16.0/assets/js/935f2afb.2f263db7.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[8581],{5610:t=>{t.exports=JSON.parse('{"pluginId":"default","version":"current","label":"Next","banner":null,"badge":false,"noIndex":false,"className":"docs-version-current","isLast":true,"docsSidebars":{"autoSidebar":[{"type":"link","label":"Introduction","href":"/docs/0.16.0/","docId":"index"},{"type":"category","label":"Getting Started","collapsible":true,"collapsed":false,"items":[{"type":"link","label":"Rust","href":"/docs/0.16.0/getting-started/rust","docId":"getting-started/rust"},{"type":"link","label":"JavaScript (Web Browser)","href":"/docs/0.16.0/getting-started/javascript-web","docId":"getting-started/javascript-web"},{"type":"link","label":"Node.js","href":"/docs/0.16.0/getting-started/nodejs","docId":"getting-started/nodejs"},{"type":"link","label":"Command-Line Interface","href":"/docs/0.16.0/getting-started/cli","docId":"getting-started/cli"}]},{"type":"category","label":"SQL Syntax","collapsible":true,"collapsed":false,"items":[{"type":"link","label":"Introduction","href":"/docs/0.16.0/sql-syntax/intro","docId":"sql-syntax/intro"},{"type":"category","label":"Statements","collapsible":true,"collapsed":true,"items":[{"type":"category","label":"Querying","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"WHERE","href":"/docs/0.16.0/sql-syntax/statements/querying/where","docId":"sql-syntax/statements/querying/where"},{"type":"link","label":"JOIN","href":"/docs/0.16.0/sql-syntax/statements/querying/join","docId":"sql-syntax/statements/querying/join"},{"type":"link","label":"LIMIT & OFFSET","href":"/docs/0.16.0/sql-syntax/statements/querying/limit","docId":"sql-syntax/statements/querying/limit"},{"type":"link","label":"Aggregation","href":"/docs/0.16.0/sql-syntax/statements/querying/aggregation","docId":"sql-syntax/statements/querying/aggregation"},{"type":"link","label":"Schemaless Data","href":"/docs/0.16.0/sql-syntax/statements/querying/schemaless","docId":"sql-syntax/statements/querying/schemaless"}]},{"type":"category","label":"Data definition","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"CREATE TABLE","href":"/docs/0.16.0/sql-syntax/statements/data-definition/create-table","docId":"sql-syntax/statements/data-definition/create-table"},{"type":"link","label":"DROP TABLE","href":"/docs/0.16.0/sql-syntax/statements/data-definition/drop-table","docId":"sql-syntax/statements/data-definition/drop-table"},{"type":"link","label":"CREATE INDEX","href":"/docs/0.16.0/sql-syntax/statements/data-definition/create-index","docId":"sql-syntax/statements/data-definition/create-index"},{"type":"link","label":"DROP INDEX","href":"/docs/0.16.0/sql-syntax/statements/data-definition/drop-index","docId":"sql-syntax/statements/data-definition/drop-index"},{"type":"link","label":"ALTER TABLE","href":"/docs/0.16.0/sql-syntax/statements/data-definition/alter-table","docId":"sql-syntax/statements/data-definition/alter-table"}]},{"type":"category","label":"Data manipulation","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"INSERT","href":"/docs/0.16.0/sql-syntax/statements/data-manipulation/insert","docId":"sql-syntax/statements/data-manipulation/insert"},{"type":"link","label":"UPDATE","href":"/docs/0.16.0/sql-syntax/statements/data-manipulation/update","docId":"sql-syntax/statements/data-manipulation/update"},{"type":"link","label":"DELETE","href":"/docs/0.16.0/sql-syntax/statements/data-manipulation/delete","docId":"sql-syntax/statements/data-manipulation/delete"}]},{"type":"link","label":"Transaction","href":"/docs/0.16.0/sql-syntax/statements/transaction","docId":"sql-syntax/statements/transaction"},{"type":"category","label":"Metadata","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"SHOW TABLES","href":"/docs/0.16.0/sql-syntax/statements/metadata/show-tables","docId":"sql-syntax/statements/metadata/show-tables"},{"type":"link","label":"Data Dictionary","href":"/docs/0.16.0/sql-syntax/statements/metadata/data-dictionary","docId":"sql-syntax/statements/metadata/data-dictionary"}]}]},{"type":"category","label":"Data types","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"BOOLEAN","href":"/docs/0.16.0/sql-syntax/data-types/boolean","docId":"sql-syntax/data-types/boolean"},{"type":"link","label":"Integer Types","href":"/docs/0.16.0/sql-syntax/data-types/integers","docId":"sql-syntax/data-types/integers"},{"type":"link","label":"FLOAT","href":"/docs/0.16.0/sql-syntax/data-types/float","docId":"sql-syntax/data-types/float"},{"type":"link","label":"TEXT","href":"/docs/0.16.0/sql-syntax/data-types/text","docId":"sql-syntax/data-types/text"},{"type":"link","label":"DECIMAL","href":"/docs/0.16.0/sql-syntax/data-types/decimal","docId":"sql-syntax/data-types/decimal"},{"type":"link","label":"DATE","href":"/docs/0.16.0/sql-syntax/data-types/date","docId":"sql-syntax/data-types/date"},{"type":"link","label":"TIMESTAMP","href":"/docs/0.16.0/sql-syntax/data-types/timestamp","docId":"sql-syntax/data-types/timestamp"},{"type":"link","label":"TIME","href":"/docs/0.16.0/sql-syntax/data-types/time","docId":"sql-syntax/data-types/time"},{"type":"link","label":"INTERVAL","href":"/docs/0.16.0/sql-syntax/data-types/interval","docId":"sql-syntax/data-types/interval"},{"type":"link","label":"LIST","href":"/docs/0.16.0/sql-syntax/data-types/list","docId":"sql-syntax/data-types/list"},{"type":"link","label":"MAP","href":"/docs/0.16.0/sql-syntax/data-types/map","docId":"sql-syntax/data-types/map"},{"type":"link","label":"BYTEA","href":"/docs/0.16.0/sql-syntax/data-types/bytea","docId":"sql-syntax/data-types/bytea"},{"type":"link","label":"INET","href":"/docs/0.16.0/sql-syntax/data-types/inet","docId":"sql-syntax/data-types/inet"},{"type":"link","label":"UUID","href":"/docs/0.16.0/sql-syntax/data-types/uuid","docId":"sql-syntax/data-types/uuid"}]},{"type":"category","label":"Functions","collapsible":true,"collapsed":true,"items":[{"type":"category","label":"Text","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"ASCII","href":"/docs/0.16.0/sql-syntax/functions/text/ascii","docId":"sql-syntax/functions/text/ascii"},{"type":"link","label":"CHR","href":"/docs/0.16.0/sql-syntax/functions/text/chr","docId":"sql-syntax/functions/text/chr"},{"type":"link","label":"CONCAT_WS","href":"/docs/0.16.0/sql-syntax/functions/text/concat-ws","docId":"sql-syntax/functions/text/concat-ws"},{"type":"link","label":"CONCAT","href":"/docs/0.16.0/sql-syntax/functions/text/concat","docId":"sql-syntax/functions/text/concat"},{"type":"link","label":"FIND_IDX","href":"/docs/0.16.0/sql-syntax/functions/text/find-idx","docId":"sql-syntax/functions/text/find-idx"},{"type":"link","label":"INITCAP","href":"/docs/0.16.0/sql-syntax/functions/text/initcap","docId":"sql-syntax/functions/text/initcap"},{"type":"link","label":"LEFT","href":"/docs/0.16.0/sql-syntax/functions/text/left","docId":"sql-syntax/functions/text/left"},{"type":"link","label":"LOWER","href":"/docs/0.16.0/sql-syntax/functions/text/lower","docId":"sql-syntax/functions/text/lower"},{"type":"link","label":"LPAD","href":"/docs/0.16.0/sql-syntax/functions/text/lpad","docId":"sql-syntax/functions/text/lpad"},{"type":"link","label":"LTRIM","href":"/docs/0.16.0/sql-syntax/functions/text/ltrim","docId":"sql-syntax/functions/text/ltrim"},{"type":"link","label":"POSITION","href":"/docs/0.16.0/sql-syntax/functions/text/position","docId":"sql-syntax/functions/text/position"},{"type":"link","label":"REPEAT","href":"/docs/0.16.0/sql-syntax/functions/text/repeat","docId":"sql-syntax/functions/text/repeat"},{"type":"link","label":"REVERSE","href":"/docs/0.16.0/sql-syntax/functions/text/reverse","docId":"sql-syntax/functions/text/reverse"},{"type":"link","label":"RIGHT","href":"/docs/0.16.0/sql-syntax/functions/text/right","docId":"sql-syntax/functions/text/right"},{"type":"link","label":"RPAD","href":"/docs/0.16.0/sql-syntax/functions/text/rpad","docId":"sql-syntax/functions/text/rpad"},{"type":"link","label":"RTRIM","href":"/docs/0.16.0/sql-syntax/functions/text/rtrim","docId":"sql-syntax/functions/text/rtrim"},{"type":"link","label":"SUBSTR","href":"/docs/0.16.0/sql-syntax/functions/text/substr","docId":"sql-syntax/functions/text/substr"},{"type":"link","label":"TRIM","href":"/docs/0.16.0/sql-syntax/functions/text/trim","docId":"sql-syntax/functions/text/trim"},{"type":"link","label":"UPPER","href":"/docs/0.16.0/sql-syntax/functions/text/upper","docId":"sql-syntax/functions/text/upper"}]},{"type":"category","label":"Math","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"ABS","href":"/docs/0.16.0/sql-syntax/functions/math/abs","docId":"sql-syntax/functions/math/abs"},{"type":"link","label":"ACOS","href":"/docs/0.16.0/sql-syntax/functions/math/acos","docId":"sql-syntax/functions/math/acos"},{"type":"link","label":"ASIN","href":"/docs/0.16.0/sql-syntax/functions/math/asin","docId":"sql-syntax/functions/math/asin"},{"type":"link","label":"ATAN","href":"/docs/0.16.0/sql-syntax/functions/math/atan","docId":"sql-syntax/functions/math/atan"},{"type":"link","label":"CEIL","href":"/docs/0.16.0/sql-syntax/functions/math/ceil","docId":"sql-syntax/functions/math/ceil"},{"type":"link","label":"COS","href":"/docs/0.16.0/sql-syntax/functions/math/cos","docId":"sql-syntax/functions/math/cos"},{"type":"link","label":"DEGREES","href":"/docs/0.16.0/sql-syntax/functions/math/degrees","docId":"sql-syntax/functions/math/degrees"},{"type":"link","label":"DIV","href":"/docs/0.16.0/sql-syntax/functions/math/div","docId":"sql-syntax/functions/math/div"},{"type":"link","label":"EXP","href":"/docs/0.16.0/sql-syntax/functions/math/exp","docId":"sql-syntax/functions/math/exp"},{"type":"link","label":"FLOOR","href":"/docs/0.16.0/sql-syntax/functions/math/floor","docId":"sql-syntax/functions/math/floor"},{"type":"link","label":"GCD","href":"/docs/0.16.0/sql-syntax/functions/math/gcd","docId":"sql-syntax/functions/math/gcd"},{"type":"link","label":"LCM","href":"/docs/0.16.0/sql-syntax/functions/math/lcm","docId":"sql-syntax/functions/math/lcm"},{"type":"link","label":"LN","href":"/docs/0.16.0/sql-syntax/functions/math/ln","docId":"sql-syntax/functions/math/ln"},{"type":"link","label":"LOG","href":"/docs/0.16.0/sql-syntax/functions/math/log","docId":"sql-syntax/functions/math/log"},{"type":"link","label":"LOG10","href":"/docs/0.16.0/sql-syntax/functions/math/log10","docId":"sql-syntax/functions/math/log10"},{"type":"link","label":"LOG2","href":"/docs/0.16.0/sql-syntax/functions/math/log2","docId":"sql-syntax/functions/math/log2"},{"type":"link","label":"MOD","href":"/docs/0.16.0/sql-syntax/functions/math/mod","docId":"sql-syntax/functions/math/mod"},{"type":"link","label":"PI","href":"/docs/0.16.0/sql-syntax/functions/math/pi","docId":"sql-syntax/functions/math/pi"},{"type":"link","label":"POWER","href":"/docs/0.16.0/sql-syntax/functions/math/power","docId":"sql-syntax/functions/math/power"},{"type":"link","label":"RADIANS","href":"/docs/0.16.0/sql-syntax/functions/math/radians","docId":"sql-syntax/functions/math/radians"},{"type":"link","label":"RAND","href":"/docs/0.16.0/sql-syntax/functions/math/rand","docId":"sql-syntax/functions/math/rand"},{"type":"link","label":"ROUND","href":"/docs/0.16.0/sql-syntax/functions/math/round","docId":"sql-syntax/functions/math/round"},{"type":"link","label":"SIGN","href":"/docs/0.16.0/sql-syntax/functions/math/sign","docId":"sql-syntax/functions/math/sign"},{"type":"link","label":"SIN","href":"/docs/0.16.0/sql-syntax/functions/math/sin","docId":"sql-syntax/functions/math/sin"},{"type":"link","label":"SQRT","href":"/docs/0.16.0/sql-syntax/functions/math/sqrt","docId":"sql-syntax/functions/math/sqrt"},{"type":"link","label":"TAN","href":"/docs/0.16.0/sql-syntax/functions/math/tan","docId":"sql-syntax/functions/math/tan"}]},{"type":"category","label":"Date & Time","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"EXTRACT","href":"/docs/0.16.0/sql-syntax/functions/datetime/extract","docId":"sql-syntax/functions/datetime/extract"},{"type":"link","label":"FORMAT","href":"/docs/0.16.0/sql-syntax/functions/datetime/format","docId":"sql-syntax/functions/datetime/format"},{"type":"link","label":"NOW","href":"/docs/0.16.0/sql-syntax/functions/datetime/now","docId":"sql-syntax/functions/datetime/now"},{"type":"link","label":"TO_DATE","href":"/docs/0.16.0/sql-syntax/functions/datetime/to-date","docId":"sql-syntax/functions/datetime/to-date"},{"type":"link","label":"TO_TIME","href":"/docs/0.16.0/sql-syntax/functions/datetime/to-time","docId":"sql-syntax/functions/datetime/to-time"},{"type":"link","label":"TO_TIMESTAMP","href":"/docs/0.16.0/sql-syntax/functions/datetime/to-timestamp","docId":"sql-syntax/functions/datetime/to-timestamp"}]},{"type":"category","label":"List & Map","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"APPEND","href":"/docs/0.16.0/sql-syntax/functions/list-map/append","docId":"sql-syntax/functions/list-map/append"},{"type":"link","label":"CONCAT","href":"/docs/0.16.0/sql-syntax/functions/list-map/concat","docId":"sql-syntax/functions/list-map/concat"},{"type":"link","label":"PREPEND","href":"/docs/0.16.0/sql-syntax/functions/list-map/prepend","docId":"sql-syntax/functions/list-map/prepend"},{"type":"link","label":"SLICE","href":"/docs/0.16.0/sql-syntax/functions/list-map/slice","docId":"sql-syntax/functions/list-map/slice"},{"type":"link","label":"SQL Function - \\"SPLICE\\"","href":"/docs/0.16.0/sql-syntax/functions/list-map/splice","docId":"sql-syntax/functions/list-map/splice"}]},{"type":"category","label":"Geometry","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"CALC_DISTANCE","href":"/docs/0.16.0/sql-syntax/functions/geometry/calc-distance","docId":"sql-syntax/functions/geometry/calc-distance"},{"type":"link","label":"GET_X","href":"/docs/0.16.0/sql-syntax/functions/geometry/get-x","docId":"sql-syntax/functions/geometry/get-x"},{"type":"link","label":"GET_Y","href":"/docs/0.16.0/sql-syntax/functions/geometry/get-y","docId":"sql-syntax/functions/geometry/get-y"},{"type":"link","label":"POINT","href":"/docs/0.16.0/sql-syntax/functions/geometry/point","docId":"sql-syntax/functions/geometry/point"}]},{"type":"category","label":"Others","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"CAST","href":"/docs/0.16.0/sql-syntax/functions/others/cast","docId":"sql-syntax/functions/others/cast"},{"type":"link","label":"GENERATE_UUID","href":"/docs/0.16.0/sql-syntax/functions/others/generate-uuid","docId":"sql-syntax/functions/others/generate-uuid"},{"type":"link","label":"IFNULL","href":"/docs/0.16.0/sql-syntax/functions/others/ifnull","docId":"sql-syntax/functions/others/ifnull"}]}]}]},{"type":"category","label":"AST Builder","collapsible":true,"collapsed":false,"items":[{"type":"link","label":"Introduction","href":"/docs/0.16.0/ast-builder/intro","docId":"ast-builder/intro"},{"type":"category","label":"Statements","collapsible":true,"collapsed":true,"items":[{"type":"category","label":"Querying","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Fetching Data from Storage","href":"/docs/0.16.0/ast-builder/statements/querying/fetching-data-from-storage","docId":"ast-builder/statements/querying/fetching-data-from-storage"},{"type":"link","label":"Using Preloaded Data","href":"/docs/0.16.0/ast-builder/statements/querying/using-preloaded-data","docId":"ast-builder/statements/querying/using-preloaded-data"},{"type":"link","label":"Creating Derived Subqueries","href":"/docs/0.16.0/ast-builder/statements/querying/creating-derived-subqueries","docId":"ast-builder/statements/querying/creating-derived-subqueries"},{"type":"link","label":"Data Aggregation","href":"/docs/0.16.0/ast-builder/statements/querying/data-aggregation","docId":"ast-builder/statements/querying/data-aggregation"},{"type":"link","label":"Data Injection","href":"/docs/0.16.0/ast-builder/statements/querying/data-injection","docId":"ast-builder/statements/querying/data-injection"},{"type":"link","label":"Data Joining","href":"/docs/0.16.0/ast-builder/statements/querying/data-joining","docId":"ast-builder/statements/querying/data-joining"},{"type":"link","label":"Data Selection and Projection","href":"/docs/0.16.0/ast-builder/statements/querying/data-selection-and-projection","docId":"ast-builder/statements/querying/data-selection-and-projection"},{"type":"link","label":"Data Sorting and Limiting","href":"/docs/0.16.0/ast-builder/statements/querying/data-sorting-and-limiting","docId":"ast-builder/statements/querying/data-sorting-and-limiting"}]},{"type":"category","label":"Data Manipulation","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Inserting Data","href":"/docs/0.16.0/ast-builder/statements/data-manipulation/inserting-data","docId":"ast-builder/statements/data-manipulation/inserting-data"},{"type":"link","label":"Updating Data","href":"/docs/0.16.0/ast-builder/statements/data-manipulation/updating-data","docId":"ast-builder/statements/data-manipulation/updating-data"},{"type":"link","label":"Deleting Data","href":"/docs/0.16.0/ast-builder/statements/data-manipulation/deleting-data","docId":"ast-builder/statements/data-manipulation/deleting-data"}]}]},{"type":"category","label":"Expressions","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Conditional","href":"/docs/0.16.0/ast-builder/expressions/conditional","docId":"ast-builder/expressions/conditional"},{"type":"link","label":"Nested","href":"/docs/0.16.0/ast-builder/expressions/nested","docId":"ast-builder/expressions/nested"},{"type":"link","label":"Operator Based","href":"/docs/0.16.0/ast-builder/expressions/operator-based","docId":"ast-builder/expressions/operator-based"},{"type":"link","label":"Pattern Matching","href":"/docs/0.16.0/ast-builder/expressions/pattern-matching","docId":"ast-builder/expressions/pattern-matching"},{"type":"link","label":"Value Checking","href":"/docs/0.16.0/ast-builder/expressions/value-checking","docId":"ast-builder/expressions/value-checking"}]},{"type":"category","label":"Functions","collapsible":true,"collapsed":true,"items":[{"type":"category","label":"Text","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Case Conversion","href":"/docs/0.16.0/ast-builder/functions/text/case-conversion","docId":"ast-builder/functions/text/case-conversion"},{"type":"link","label":"Character Conversion","href":"/docs/0.16.0/ast-builder/functions/text/character-conversion","docId":"ast-builder/functions/text/character-conversion"},{"type":"link","label":"Padding","href":"/docs/0.16.0/ast-builder/functions/text/padding","docId":"ast-builder/functions/text/padding"},{"type":"link","label":"Position and Indexing","href":"/docs/0.16.0/ast-builder/functions/text/position-and-indexing","docId":"ast-builder/functions/text/position-and-indexing"},{"type":"link","label":"Text Manipulation","href":"/docs/0.16.0/ast-builder/functions/text/text-manipulation","docId":"ast-builder/functions/text/text-manipulation"},{"type":"link","label":"Trimming","href":"/docs/0.16.0/ast-builder/functions/text/trimming","docId":"ast-builder/functions/text/trimming"}]},{"type":"category","label":"Math","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Basic Arithmetic","href":"/docs/0.16.0/ast-builder/functions/math/basic-arithmetic","docId":"ast-builder/functions/math/basic-arithmetic"},{"type":"link","label":"Conversion","href":"/docs/0.16.0/ast-builder/functions/math/conversion","docId":"ast-builder/functions/math/conversion"},{"type":"link","label":"Logarithmic and Exponential","href":"/docs/0.16.0/ast-builder/functions/math/logarithmic-and-exponential","docId":"ast-builder/functions/math/logarithmic-and-exponential"},{"type":"link","label":"Rounding","href":"/docs/0.16.0/ast-builder/functions/math/rounding","docId":"ast-builder/functions/math/rounding"},{"type":"link","label":"Special Mathematical","href":"/docs/0.16.0/ast-builder/functions/math/special-mathematical","docId":"ast-builder/functions/math/special-mathematical"},{"type":"link","label":"Trigonometric","href":"/docs/0.16.0/ast-builder/functions/math/trigonometric","docId":"ast-builder/functions/math/trigonometric"}]},{"type":"category","label":"Date & Time","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Conversion","href":"/docs/0.16.0/ast-builder/functions/date-&-time/conversion","docId":"ast-builder/functions/date-&-time/conversion"},{"type":"link","label":"Current Date and Time","href":"/docs/0.16.0/ast-builder/functions/date-&-time/current-date-and-time","docId":"ast-builder/functions/date-&-time/current-date-and-time"},{"type":"link","label":"Date and Time Extraction","href":"/docs/0.16.0/ast-builder/functions/date-&-time/date-and-time-extraction","docId":"ast-builder/functions/date-&-time/date-and-time-extraction"},{"type":"link","label":"Formatting","href":"/docs/0.16.0/ast-builder/functions/date-&-time/formatting","docId":"ast-builder/functions/date-&-time/formatting"}]},{"type":"category","label":"List & Map","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"List and Map Concatenation","href":"/docs/0.16.0/ast-builder/functions/list-&-map/list-and-map-concatenation","docId":"ast-builder/functions/list-&-map/list-and-map-concatenation"},{"type":"link","label":"List Manipulation","href":"/docs/0.16.0/ast-builder/functions/list-&-map/list-manipulation","docId":"ast-builder/functions/list-&-map/list-manipulation"}]},{"type":"category","label":"Geometry","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Coordinate Extraction","href":"/docs/0.16.0/ast-builder/functions/geometry/coordinate-extraction","docId":"ast-builder/functions/geometry/coordinate-extraction"},{"type":"link","label":"Distance Calculation","href":"/docs/0.16.0/ast-builder/functions/geometry/distance-calculation","docId":"ast-builder/functions/geometry/distance-calculation"},{"type":"link","label":"Point Creation","href":"/docs/0.16.0/ast-builder/functions/geometry/point-creation","docId":"ast-builder/functions/geometry/point-creation"}]},{"type":"category","label":"Others","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Null Handling","href":"/docs/0.16.0/ast-builder/functions/others/null-handling","docId":"ast-builder/functions/others/null-handling"},{"type":"link","label":"Type Conversion","href":"/docs/0.16.0/ast-builder/functions/others/type-conversion","docId":"ast-builder/functions/others/type-conversion"},{"type":"link","label":"Unique Identifier","href":"/docs/0.16.0/ast-builder/functions/others/unique-identifier","docId":"ast-builder/functions/others/unique-identifier"}]}]}]},{"type":"category","label":"Storages","collapsible":true,"collapsed":false,"items":[{"type":"link","label":"Introduction","href":"/docs/0.16.0/storages/intro","docId":"storages/intro"},{"type":"category","label":"Supported Storages","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Composite Storage","href":"/docs/0.16.0/storages/supported-storages/composite-storage","docId":"storages/supported-storages/composite-storage"},{"type":"link","label":"CSV Storage","href":"/docs/0.16.0/storages/supported-storages/csv-storage","docId":"storages/supported-storages/csv-storage"},{"type":"link","label":"IndexedDB Storage","href":"/docs/0.16.0/storages/supported-storages/idb-storage","docId":"storages/supported-storages/idb-storage"},{"type":"link","label":"JSON Storage","href":"/docs/0.16.0/storages/supported-storages/json-storage","docId":"storages/supported-storages/json-storage"},{"type":"link","label":"Memory Storage","href":"/docs/0.16.0/storages/supported-storages/memory-storage","docId":"storages/supported-storages/memory-storage"},{"type":"link","label":"Parquet Storage","href":"/docs/0.16.0/storages/supported-storages/parquet-storage","docId":"storages/supported-storages/parquet-storage"},{"type":"link","label":"Shared Memory Storage","href":"/docs/0.16.0/storages/supported-storages/shared-memory-storage","docId":"storages/supported-storages/shared-memory-storage"},{"type":"link","label":"Sled Storage","href":"/docs/0.16.0/storages/supported-storages/sled-storage","docId":"storages/supported-storages/sled-storage"},{"type":"link","label":"WebStorage (local & session)","href":"/docs/0.16.0/storages/supported-storages/web-storage","docId":"storages/supported-storages/web-storage"}]},{"type":"category","label":"Developing Custom Storages","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Introduction","href":"/docs/0.16.0/storages/developing-custom-storages/intro","docId":"storages/developing-custom-storages/intro"},{"type":"category","label":"Understanding Store traits","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Store","href":"/docs/0.16.0/storages/developing-custom-storages/store-traits/store","docId":"storages/developing-custom-storages/store-traits/store"},{"type":"link","label":"StoreMut","href":"/docs/0.16.0/storages/developing-custom-storages/store-traits/store-mut","docId":"storages/developing-custom-storages/store-traits/store-mut"},{"type":"link","label":"AlterTable","href":"/docs/0.16.0/storages/developing-custom-storages/store-traits/alter-table","docId":"storages/developing-custom-storages/store-traits/alter-table"},{"type":"link","label":"Transaction","href":"/docs/0.16.0/storages/developing-custom-storages/store-traits/transaction","docId":"storages/developing-custom-storages/store-traits/transaction"},{"type":"link","label":"CustomFunction","href":"/docs/0.16.0/storages/developing-custom-storages/store-traits/custom-function","docId":"storages/developing-custom-storages/store-traits/custom-function"},{"type":"link","label":"CustomFunctionMut","href":"/docs/0.16.0/storages/developing-custom-storages/store-traits/custom-function-mut","docId":"storages/developing-custom-storages/store-traits/custom-function-mut"},{"type":"link","label":"Index","href":"/docs/0.16.0/storages/developing-custom-storages/store-traits/index-trait","docId":"storages/developing-custom-storages/store-traits/index-trait"},{"type":"link","label":"IndexMut","href":"/docs/0.16.0/storages/developing-custom-storages/store-traits/index-mut","docId":"storages/developing-custom-storages/store-traits/index-mut"},{"type":"link","label":"Metadata","href":"/docs/0.16.0/storages/developing-custom-storages/store-traits/metadata","docId":"storages/developing-custom-storages/store-traits/metadata"}]},{"type":"link","label":"Using the Test Suite","href":"/docs/0.16.0/storages/developing-custom-storages/using-test-suite","docId":"storages/developing-custom-storages/using-test-suite"}]}]}]},"docs":{"ast-builder/expressions/conditional":{"id":"ast-builder/expressions/conditional","title":"Conditional","description":"Todo","sidebar":"autoSidebar"},"ast-builder/expressions/nested":{"id":"ast-builder/expressions/nested","title":"Nested","description":"Todo","sidebar":"autoSidebar"},"ast-builder/expressions/operator-based":{"id":"ast-builder/expressions/operator-based","title":"Operator Based","description":"Todo","sidebar":"autoSidebar"},"ast-builder/expressions/pattern-matching":{"id":"ast-builder/expressions/pattern-matching","title":"Pattern Matching","description":"Pattern matching is a crucial feature in SQL that allows you to match rows based on specific patterns in a column. GlueSQL provides 4 pattern matching operators: like, ilike, notlike, and notilike.","sidebar":"autoSidebar"},"ast-builder/expressions/value-checking":{"id":"ast-builder/expressions/value-checking","title":"Value Checking","description":"Todo","sidebar":"autoSidebar"},"ast-builder/functions/date-&-time/conversion":{"id":"ast-builder/functions/date-&-time/conversion","title":"Conversion","description":"GlueSQL provides date and time conversion functions that allow you to convert text data to datetime data types such as Date, Time, and Timestamp. These functions are todate, totime, and to_timestamp.","sidebar":"autoSidebar"},"ast-builder/functions/date-&-time/current-date-and-time":{"id":"ast-builder/functions/date-&-time/current-date-and-time","title":"Current Date and Time","description":"GlueSQL provides a function to get the current date and time: now.","sidebar":"autoSidebar"},"ast-builder/functions/date-&-time/date-and-time-extraction":{"id":"ast-builder/functions/date-&-time/date-and-time-extraction","title":"Date and Time Extraction","description":"Todo","sidebar":"autoSidebar"},"ast-builder/functions/date-&-time/formatting":{"id":"ast-builder/functions/date-&-time/formatting","title":"Formatting","description":"In GlueSQL, you can format date, time, and timestamp values to a specific format using the format function.","sidebar":"autoSidebar"},"ast-builder/functions/geometry/coordinate-extraction":{"id":"ast-builder/functions/geometry/coordinate-extraction","title":"Coordinate Extraction","description":"Todo","sidebar":"autoSidebar"},"ast-builder/functions/geometry/distance-calculation":{"id":"ast-builder/functions/geometry/distance-calculation","title":"Distance Calculation","description":"Todo","sidebar":"autoSidebar"},"ast-builder/functions/geometry/point-creation":{"id":"ast-builder/functions/geometry/point-creation","title":"Point Creation","description":"Todo","sidebar":"autoSidebar"},"ast-builder/functions/list-&-map/list-and-map-concatenation":{"id":"ast-builder/functions/list-&-map/list-and-map-concatenation","title":"List and Map Concatenation","description":"Todo","sidebar":"autoSidebar"},"ast-builder/functions/list-&-map/list-manipulation":{"id":"ast-builder/functions/list-&-map/list-manipulation","title":"List Manipulation","description":"Todo","sidebar":"autoSidebar"},"ast-builder/functions/math/basic-arithmetic":{"id":"ast-builder/functions/math/basic-arithmetic","title":"Basic Arithmetic","description":"GlueSQL provides a number of basic arithmetic operations such as absolute value (abs), division (divide), modulo (modulo), greatest common divisor (gcd), and least common multiple (lcm).","sidebar":"autoSidebar"},"ast-builder/functions/math/conversion":{"id":"ast-builder/functions/math/conversion","title":"Conversion","description":"The AST (Abstract Syntax Tree) Builder in GlueSQL provides mathematical conversion functions like degrees and radians. These functions convert angles expressed in radians to degrees and vice versa.","sidebar":"autoSidebar"},"ast-builder/functions/math/logarithmic-and-exponential":{"id":"ast-builder/functions/math/logarithmic-and-exponential","title":"Logarithmic and Exponential","description":"Todo","sidebar":"autoSidebar"},"ast-builder/functions/math/rounding":{"id":"ast-builder/functions/math/rounding","title":"Rounding","description":"The AST (Abstract Syntax Tree) Builder in GlueSQL provides several mathematical functions, including round, ceil, and floor. These functions are used to perform rounding operations on floating-point numbers.","sidebar":"autoSidebar"},"ast-builder/functions/math/special-mathematical":{"id":"ast-builder/functions/math/special-mathematical","title":"Special Mathematical","description":"Todo","sidebar":"autoSidebar"},"ast-builder/functions/math/trigonometric":{"id":"ast-builder/functions/math/trigonometric","title":"Trigonometric","description":"Todo","sidebar":"autoSidebar"},"ast-builder/functions/others/null-handling":{"id":"ast-builder/functions/others/null-handling","title":"Null Handling","description":"In some cases, you may need to handle NULL values in your database. GlueSQL provides a function called ifnull to handle these cases.","sidebar":"autoSidebar"},"ast-builder/functions/others/type-conversion":{"id":"ast-builder/functions/others/type-conversion","title":"Type Conversion","description":"Todo","sidebar":"autoSidebar"},"ast-builder/functions/others/unique-identifier":{"id":"ast-builder/functions/others/unique-identifier","title":"Unique Identifier","description":"Todo","sidebar":"autoSidebar"},"ast-builder/functions/text/case-conversion":{"id":"ast-builder/functions/text/case-conversion","title":"Case Conversion","description":"GlueSQL provides several text case conversion functions that allow you to convert text data to upper case, lower case or capitalize each word in a string.","sidebar":"autoSidebar"},"ast-builder/functions/text/character-conversion":{"id":"ast-builder/functions/text/character-conversion","title":"Character Conversion","description":"The AST Builder API in GlueSQL allows you to execute ascii and chr functions for character conversion.","sidebar":"autoSidebar"},"ast-builder/functions/text/padding":{"id":"ast-builder/functions/text/padding","title":"Padding","description":"The AST Builder API in GlueSQL allows you to execute lpad and rpad functions for text padding.","sidebar":"autoSidebar"},"ast-builder/functions/text/position-and-indexing":{"id":"ast-builder/functions/text/position-and-indexing","title":"Position and Indexing","description":"GlueSQL provides several functions for text manipulation, including finding the index of a substring (find_idx), finding the position of a substring (position), and getting the leftmost or rightmost characters (left and right).","sidebar":"autoSidebar"},"ast-builder/functions/text/text-manipulation":{"id":"ast-builder/functions/text/text-manipulation","title":"Text Manipulation","description":"Todo","sidebar":"autoSidebar"},"ast-builder/functions/text/trimming":{"id":"ast-builder/functions/text/trimming","title":"Trimming","description":"GlueSQL provides several text trimming functions that allow you to remove leading or trailing characters from a text string.","sidebar":"autoSidebar"},"ast-builder/intro":{"id":"ast-builder/intro","title":"Introduction","description":"GlueSQL offers two ways to create and execute queries: using SQL statements or using the AST Builder. In this introductory page, we will focus on the AST Builder.","sidebar":"autoSidebar"},"ast-builder/statements/data-manipulation/deleting-data":{"id":"ast-builder/statements/data-manipulation/deleting-data","title":"Deleting Data","description":"In this section, we will discuss how to delete data from a table using GlueSQL.","sidebar":"autoSidebar"},"ast-builder/statements/data-manipulation/inserting-data":{"id":"ast-builder/statements/data-manipulation/inserting-data","title":"Inserting Data","description":"In this section, we will discuss how to insert data into a table using GlueSQL.","sidebar":"autoSidebar"},"ast-builder/statements/data-manipulation/updating-data":{"id":"ast-builder/statements/data-manipulation/updating-data","title":"Updating Data","description":"In this section, we will discuss how to update data in a table using GlueSQL.","sidebar":"autoSidebar"},"ast-builder/statements/querying/creating-derived-subqueries":{"id":"ast-builder/statements/querying/creating-derived-subqueries","title":"Creating Derived Subqueries","description":"This document covers the aliasas functionality of the AST Builder in the GlueSQL project. The aliasas method allows you to create a derived subquery, which is similar to subqueries in SQL. It gives you the ability to use the output of a query as a table to perform further queries.","sidebar":"autoSidebar"},"ast-builder/statements/querying/data-aggregation":{"id":"ast-builder/statements/querying/data-aggregation","title":"Data Aggregation","description":"The AST Builder API in GlueSQL allows you to construct SQL queries programmatically. This page provides an introduction to data aggregation using the AST Builder API.","sidebar":"autoSidebar"},"ast-builder/statements/querying/data-injection":{"id":"ast-builder/statements/querying/data-injection","title":"Data Injection","description":"Todo","sidebar":"autoSidebar"},"ast-builder/statements/querying/data-joining":{"id":"ast-builder/statements/querying/data-joining","title":"Data Joining","description":"Todo","sidebar":"autoSidebar"},"ast-builder/statements/querying/data-selection-and-projection":{"id":"ast-builder/statements/querying/data-selection-and-projection","title":"Data Selection and Projection","description":"Todo","sidebar":"autoSidebar"},"ast-builder/statements/querying/data-sorting-and-limiting":{"id":"ast-builder/statements/querying/data-sorting-and-limiting","title":"Data Sorting and Limiting","description":"Todo","sidebar":"autoSidebar"},"ast-builder/statements/querying/fetching-data-from-storage":{"id":"ast-builder/statements/querying/fetching-data-from-storage","title":"Fetching Data from Storage","description":"The AST Builder provides a powerful and flexible way to query data from your tables, similar to SQL\'s SELECT statement. This guide will show you how to use the AST Builder\'s table(\\"foo\\").select() method to perform various query types, including filtering, joining, grouping, ordering, and pagination.","sidebar":"autoSidebar"},"ast-builder/statements/querying/using-preloaded-data":{"id":"ast-builder/statements/querying/using-preloaded-data","title":"Using Preloaded Data","description":"This guide will show you how to use AST Builder to query data that has already been loaded into memory, as opposed to querying data from storage. This is similar to SQL\'s VALUES functionality.","sidebar":"autoSidebar"},"getting-started/cli":{"id":"getting-started/cli","title":"Command-Line Interface","description":"Introduction","sidebar":"autoSidebar"},"getting-started/javascript-web":{"id":"getting-started/javascript-web","title":"JavaScript (Web Browser)","description":"GlueSQL is a SQL database engine written in Rust, compiled to WebAssembly, and can be used in JavaScript. This guide will walk you through the process of installing and using the GlueSQL package.","sidebar":"autoSidebar"},"getting-started/nodejs":{"id":"getting-started/nodejs","title":"Node.js","description":"This guide will help you get started with GlueSQL in a Node.js project. First, install the gluesql package using npm by running the following command in your terminal:","sidebar":"autoSidebar"},"getting-started/rust":{"id":"getting-started/rust","title":"Rust","description":"To install and use GlueSQL in your Rust project, you\'ll first need to add it as a dependency from crates.io. You can do this by adding the following lines to your Cargo.toml file:","sidebar":"autoSidebar"},"index":{"id":"index","title":"Introduction","description":"crates.io","sidebar":"autoSidebar"},"sql-syntax/data-types/boolean":{"id":"sql-syntax/data-types/boolean","title":"BOOLEAN","description":"The BOOLEAN data type in SQL is used to store boolean values, which can be either TRUE or FALSE. This data type is useful for representing binary states or conditions in your data.","sidebar":"autoSidebar"},"sql-syntax/data-types/bytea":{"id":"sql-syntax/data-types/bytea","title":"BYTEA","description":"The BYTEA data type in SQL is used to store binary data, such as images, audio files, or any other type of data that needs to be stored in its raw form. In GlueSQL, the BYTEA data type is represented as a sequence of bytes.","sidebar":"autoSidebar"},"sql-syntax/data-types/date":{"id":"sql-syntax/data-types/date","title":"DATE","description":"In GlueSQL, the DATE data type is used to store date values in the format \'YYYY-MM-DD\'. Note that GlueSQL currently does not support timezones.","sidebar":"autoSidebar"},"sql-syntax/data-types/decimal":{"id":"sql-syntax/data-types/decimal","title":"DECIMAL","description":"The DECIMAL data type in SQL is used to store exact numeric values, making it suitable for financial calculations and other operations requiring a high level of precision without round-off errors. In GlueSQL, the DECIMAL data type is implemented using a pure Rust library, providing a 96-bit integer number, a scaling factor for specifying the decimal fraction, and a 1-bit sign.","sidebar":"autoSidebar"},"sql-syntax/data-types/float":{"id":"sql-syntax/data-types/float","title":"FLOAT","description":"The FLOAT data type in SQL is used to store floating-point numbers. In GlueSQL, the FLOAT data type represents a 64-bit floating-point number, providing the ability to store numbers with decimal values and a wide range of magnitude.","sidebar":"autoSidebar"},"sql-syntax/data-types/inet":{"id":"sql-syntax/data-types/inet","title":"INET","description":"The INET data type in SQL is used to store IPv4 and IPv6 addresses. These addresses can be compared, filtered, and sorted using standard SQL operations.","sidebar":"autoSidebar"},"sql-syntax/data-types/integers":{"id":"sql-syntax/data-types/integers","title":"Integer Types","description":"GlueSQL supports the following integer data types:","sidebar":"autoSidebar"},"sql-syntax/data-types/interval":{"id":"sql-syntax/data-types/interval","title":"INTERVAL","description":"The INTERVAL data type in GlueSQL is used to represent a period of time. In accordance with the ANSI SQL standard, several subtypes of INTERVAL can be used to represent different units of time, such as years, months, days, hours, minutes, and seconds. These subtypes are:","sidebar":"autoSidebar"},"sql-syntax/data-types/list":{"id":"sql-syntax/data-types/list","title":"LIST","description":"The LIST data type in GlueSQL is used to store ordered collections of elements, similar to JSON arrays. The elements can be any valid data supported by GlueSQL, such as numbers, strings, booleans, null, MAP, or even other nested LIST values. Although the input is provided in a JSON array format for convenience, it can store more than just JSON data.","sidebar":"autoSidebar"},"sql-syntax/data-types/map":{"id":"sql-syntax/data-types/map","title":"MAP","description":"The MAP data type in GlueSQL is used to store nested key-value pairs, similar to JSON objects. The object keys must be strings, and the values can be any valid data supported by GlueSQL, such as numbers, strings, booleans, null, or even other nested MAP values. Although the input is provided in a JSON object format for convenience, it can store more than just JSON data.","sidebar":"autoSidebar"},"sql-syntax/data-types/text":{"id":"sql-syntax/data-types/text","title":"TEXT","description":"The TEXT data type in SQL is used to store variable-length character strings. In GlueSQL, the TEXT data type is the only supported string data type, providing the ability to store and manage strings of varying lengths.","sidebar":"autoSidebar"},"sql-syntax/data-types/time":{"id":"sql-syntax/data-types/time","title":"TIME","description":"In GlueSQL, the TIME data type is used to store time values in the format \'HHSS.SSS\'. The code snippet provided demonstrates how to create a table with TIME columns, insert data into it, and perform various queries and operations on the data.","sidebar":"autoSidebar"},"sql-syntax/data-types/timestamp":{"id":"sql-syntax/data-types/timestamp","title":"TIMESTAMP","description":"In GlueSQL, the TIMESTAMP data type is used to store date and time values in the format \'YYYY-MM-DD HHSS.SSSS\'. Although timezone information can be included in the input string, GlueSQL stores all TIMESTAMP values in UTC, discarding the timezone information.","sidebar":"autoSidebar"},"sql-syntax/data-types/uuid":{"id":"sql-syntax/data-types/uuid","title":"UUID","description":"The UUID data type in SQL is used to store universally unique identifiers (UUIDs). These identifiers can be compared, filtered, and sorted using standard SQL operations.","sidebar":"autoSidebar"},"sql-syntax/functions/datetime/extract":{"id":"sql-syntax/functions/datetime/extract","title":"EXTRACT","description":"The EXTRACT function in SQL is used to retrieve a specific datetime field from a date, time, or interval.","sidebar":"autoSidebar"},"sql-syntax/functions/datetime/format":{"id":"sql-syntax/functions/datetime/format","title":"FORMAT","description":"The FORMAT function in SQL is used to format date, time, and timestamp values into a specified format.","sidebar":"autoSidebar"},"sql-syntax/functions/datetime/now":{"id":"sql-syntax/functions/datetime/now","title":"NOW","description":"The NOW() function in SQL returns the current date and time in UTC. You can use it to retrieve the current UTC timestamp, or as a default value for a TIMESTAMP column in a table.","sidebar":"autoSidebar"},"sql-syntax/functions/datetime/to-date":{"id":"sql-syntax/functions/datetime/to-date","title":"TO_DATE","description":"The TO_DATE function in SQL is used to convert a string into a DATE. This function takes two arguments, the string to be converted and a format string that specifies the format of the input string.","sidebar":"autoSidebar"},"sql-syntax/functions/datetime/to-time":{"id":"sql-syntax/functions/datetime/to-time","title":"TO_TIME","description":"The TO_TIME function in SQL is used to convert a string into a TIME. This function takes two arguments, the string to be converted and a format string that specifies the format of the input string.","sidebar":"autoSidebar"},"sql-syntax/functions/datetime/to-timestamp":{"id":"sql-syntax/functions/datetime/to-timestamp","title":"TO_TIMESTAMP","description":"The TO_TIMESTAMP function in SQL is used to convert a string into a TIMESTAMP. This function takes two arguments, the string to be converted and a format string that specifies the format of the input string.","sidebar":"autoSidebar"},"sql-syntax/functions/geometry/calc-distance":{"id":"sql-syntax/functions/geometry/calc-distance","title":"CALC_DISTANCE","description":"The CALC_DISTANCE function is used to calculate the Euclidean distance between two Point type geographical coordinates.","sidebar":"autoSidebar"},"sql-syntax/functions/geometry/get-x":{"id":"sql-syntax/functions/geometry/get-x","title":"GET_X","description":"The GET_X function returns the x-coordinate of a given POINT data type. It takes one POINT data type argument and returns a FLOAT value representing the x-coordinate.","sidebar":"autoSidebar"},"sql-syntax/functions/geometry/get-y":{"id":"sql-syntax/functions/geometry/get-y","title":"GET_Y","description":"The GET_Y function returns the y-coordinate of a given POINT data type. It takes one POINT data type argument and returns a FLOAT value representing the y-coordinate.","sidebar":"autoSidebar"},"sql-syntax/functions/geometry/point":{"id":"sql-syntax/functions/geometry/point","title":"POINT","description":"The POINT function creates a point value using the provided x and y coordinates. A point value represents a two-dimensional geometric point with a pair of floating-point numbers, often used for storing spatial data.","sidebar":"autoSidebar"},"sql-syntax/functions/list-map/append":{"id":"sql-syntax/functions/list-map/append","title":"APPEND","description":"The APPEND function in SQL is used to append an element to a list.","sidebar":"autoSidebar"},"sql-syntax/functions/list-map/concat":{"id":"sql-syntax/functions/list-map/concat","title":"CONCAT","description":"The CONCAT function is used to concatenate two or more list values together.","sidebar":"autoSidebar"},"sql-syntax/functions/list-map/prepend":{"id":"sql-syntax/functions/list-map/prepend","title":"PREPEND","description":"The PREPEND function in SQL is used to prepend an element to a list.","sidebar":"autoSidebar"},"sql-syntax/functions/list-map/slice":{"id":"sql-syntax/functions/list-map/slice","title":"SLICE","description":"The SLICE statement is a function in GlueSQL that allows you to retrieve a subsection of a list. It is analogous to slicing operations in many programming languages.","sidebar":"autoSidebar"},"sql-syntax/functions/list-map/splice":{"id":"sql-syntax/functions/list-map/splice","title":"SQL Function - \\"SPLICE\\"","description":"The \\"SPLICE\\" function in GlueSQL is used to modify elements in a list. It allows you to remove or replace elements in a list. The syntax for the \\"SPLICE\\" function is as follows:","sidebar":"autoSidebar"},"sql-syntax/functions/math/abs":{"id":"sql-syntax/functions/math/abs","title":"ABS","description":"The ABS function is used to calculate the absolute value of a number. It takes a single numeric argument and returns the absolute value of that number. The argument can be an integer, decimal, or float value.","sidebar":"autoSidebar"},"sql-syntax/functions/math/acos":{"id":"sql-syntax/functions/math/acos","title":"ACOS","description":"The ACOS function is used to calculate the arccosine (inverse cosine) of a number. It takes a single numeric argument, which should be a float value in the range of -1 to 1, and returns the arccosine of that number in radians.","sidebar":"autoSidebar"},"sql-syntax/functions/math/asin":{"id":"sql-syntax/functions/math/asin","title":"ASIN","description":"The ASIN function is used to calculate the arcsine (inverse sine) of a number. It takes a single numeric argument, which should be a float value in the range of -1 to 1, and returns the arcsine of that number in radians.","sidebar":"autoSidebar"},"sql-syntax/functions/math/atan":{"id":"sql-syntax/functions/math/atan","title":"ATAN","description":"The ATAN function is used to calculate the arctangent (inverse tangent) of a number. It takes a single numeric argument, and returns the arctangent of that number in radians.","sidebar":"autoSidebar"},"sql-syntax/functions/math/ceil":{"id":"sql-syntax/functions/math/ceil","title":"CEIL","description":"The CEIL function is used to round a number up to the nearest integer value. It takes a single floating-point or integer value as its argument and returns a floating-point value.","sidebar":"autoSidebar"},"sql-syntax/functions/math/cos":{"id":"sql-syntax/functions/math/cos","title":"COS","description":"The COS function is used to calculate the cosine of a number. It takes a single numeric argument (angle in radians) and returns the cosine of that angle.","sidebar":"autoSidebar"},"sql-syntax/functions/math/degrees":{"id":"sql-syntax/functions/math/degrees","title":"DEGREES","description":"The DEGREES function is used to convert a given angle value from radians to degrees. It takes a single numeric argument (angle in radians) and returns the angle in degrees.","sidebar":"autoSidebar"},"sql-syntax/functions/math/div":{"id":"sql-syntax/functions/math/div","title":"DIV","description":"The DIV function is used to perform integer division. It takes two arguments (a dividend and a divisor) and returns the integer quotient of the division operation. Both dividend and divisor can be FLOAT or INTEGER type. The return type of the function is INTEGER.","sidebar":"autoSidebar"},"sql-syntax/functions/math/exp":{"id":"sql-syntax/functions/math/exp","title":"EXP","description":"The EXP function is used to calculate the exponential value of a number. It takes a single FLOAT or INTEGER argument and returns a FLOAT value representing the exponential value of the given number.","sidebar":"autoSidebar"},"sql-syntax/functions/math/floor":{"id":"sql-syntax/functions/math/floor","title":"FLOOR","description":"The FLOOR function is used to round a number down to the nearest integer value. It takes a single floating-point or integer value as its argument and returns a floating-point value.","sidebar":"autoSidebar"},"sql-syntax/functions/math/gcd":{"id":"sql-syntax/functions/math/gcd","title":"GCD","description":"The GCD function is used to find the greatest common divisor (GCD) of two integers. It takes two INTEGER arguments and returns an INTEGER value representing the greatest common divisor of the given integers.","sidebar":"autoSidebar"},"sql-syntax/functions/math/lcm":{"id":"sql-syntax/functions/math/lcm","title":"LCM","description":"The LCM function is used to find the least common multiple (LCM) of two integers. It takes two INTEGER arguments and returns an INTEGER value representing the least common multiple of the given integers.","sidebar":"autoSidebar"},"sql-syntax/functions/math/ln":{"id":"sql-syntax/functions/math/ln","title":"LN","description":"The LN function is used to calculate the natural logarithm (base e) of a number. It takes a single FLOAT or INTEGER argument and returns a FLOAT value representing the natural logarithm of the given number.","sidebar":"autoSidebar"},"sql-syntax/functions/math/log":{"id":"sql-syntax/functions/math/log","title":"LOG","description":"The LOG function calculates the logarithm of a number with a specified base. It takes two FLOAT or INTEGER arguments and returns a FLOAT value representing the logarithm of the first argument with the base specified by the second argument.","sidebar":"autoSidebar"},"sql-syntax/functions/math/log10":{"id":"sql-syntax/functions/math/log10","title":"LOG10","description":"The LOG10 function is used to calculate the base-10 logarithm of a number. It takes a single FLOAT or INTEGER argument and returns a FLOAT value representing the base-10 logarithm of the given number.","sidebar":"autoSidebar"},"sql-syntax/functions/math/log2":{"id":"sql-syntax/functions/math/log2","title":"LOG2","description":"The LOG2 function is used to calculate the base-2 logarithm of a number. It takes a single FLOAT or INTEGER argument and returns a FLOAT value representing the base-2 logarithm of the given number.","sidebar":"autoSidebar"},"sql-syntax/functions/math/mod":{"id":"sql-syntax/functions/math/mod","title":"MOD","description":"The MOD function is used to calculate the remainder of a division operation. It takes two arguments (a dividend and a divisor) and returns the remainder of the division operation. Both dividend and divisor can be FLOAT or INTEGER type. The return type of the function is FLOAT.","sidebar":"autoSidebar"},"sql-syntax/functions/math/pi":{"id":"sql-syntax/functions/math/pi","title":"PI","description":"The PI function is used to retrieve the mathematical constant \u03c0 (pi), which is approximately 3.141592653589793. The function takes no arguments.","sidebar":"autoSidebar"},"sql-syntax/functions/math/power":{"id":"sql-syntax/functions/math/power","title":"POWER","description":"The POWER function is used to raise a number to the power of another number. It takes two arguments, the base and the exponent, both of which must be of the FLOAT type. The result will also be of the FLOAT type.","sidebar":"autoSidebar"},"sql-syntax/functions/math/radians":{"id":"sql-syntax/functions/math/radians","title":"RADIANS","description":"The RADIANS function is used to convert a given angle value from degrees to radians. It takes a single numeric argument (angle in degrees) and returns the angle in radians.","sidebar":"autoSidebar"},"sql-syntax/functions/math/rand":{"id":"sql-syntax/functions/math/rand","title":"RAND","description":"The RAND function is used to generate a random float value between 0 (inclusive) and 1 (exclusive). The function takes an optional seed value, which must be of the FLOAT type. If a seed value is provided, the random number generator will be initialized with that seed, producing a deterministic sequence of random numbers.","sidebar":"autoSidebar"},"sql-syntax/functions/math/round":{"id":"sql-syntax/functions/math/round","title":"ROUND","description":"The ROUND function is used to round a number to the nearest integer value. It takes a single floating-point or integer value as its argument and returns a floating-point value.","sidebar":"autoSidebar"},"sql-syntax/functions/math/sign":{"id":"sql-syntax/functions/math/sign","title":"SIGN","description":"The SIGN function is used to determine the sign of a number. It takes one argument, which must be of the FLOAT type. The result will be of the INTEGER type and can be -1, 0, or 1.","sidebar":"autoSidebar"},"sql-syntax/functions/math/sin":{"id":"sql-syntax/functions/math/sin","title":"SIN","description":"The SIN function is used to calculate the sine of a number. It takes a single numeric argument (angle in radians) and returns the sine of that angle.","sidebar":"autoSidebar"},"sql-syntax/functions/math/sqrt":{"id":"sql-syntax/functions/math/sqrt","title":"SQRT","description":"The SQRT function is used to calculate the square root of a number. It takes one argument, which must be of the FLOAT type. The result will also be of the FLOAT type.","sidebar":"autoSidebar"},"sql-syntax/functions/math/tan":{"id":"sql-syntax/functions/math/tan","title":"TAN","description":"The TAN function is used to calculate the tangent of a number. It takes a single numeric argument (angle in radians) and returns the tangent of that angle.","sidebar":"autoSidebar"},"sql-syntax/functions/others/cast":{"id":"sql-syntax/functions/others/cast","title":"CAST","description":"The CAST function is used to convert a value from one data type to another. It is commonly used when you need to change the data type of a value or a column to perform a specific operation, such as arithmetic or string concatenation.","sidebar":"autoSidebar"},"sql-syntax/functions/others/generate-uuid":{"id":"sql-syntax/functions/others/generate-uuid","title":"GENERATE_UUID","description":"The GENERATE_UUID function is an SQL function provided by GlueSQL that generates a new UUID (Universally Unique Identifier) using the version 4 UUID algorithm. A UUID is a 128-bit value used to uniquely identify items in various computing systems. Version 4 UUIDs are randomly generated and have 122 bits of randomness, which ensures a very low probability of collisions.","sidebar":"autoSidebar"},"sql-syntax/functions/others/ifnull":{"id":"sql-syntax/functions/others/ifnull","title":"IFNULL","description":"The IFNULL function is used to return the first non-null value among the provided expressions. It takes two arguments and checks if the first argument is NULL. If the first argument is NULL, it returns the second argument; otherwise, it returns the first argument.","sidebar":"autoSidebar"},"sql-syntax/functions/text/ascii":{"id":"sql-syntax/functions/text/ascii","title":"ASCII","description":"The ASCII function in SQL returns the ASCII value for the first character of the specified string.","sidebar":"autoSidebar"},"sql-syntax/functions/text/chr":{"id":"sql-syntax/functions/text/chr","title":"CHR","description":"The CHR function in SQL returns the character represented by the specified ASCII value.","sidebar":"autoSidebar"},"sql-syntax/functions/text/concat":{"id":"sql-syntax/functions/text/concat","title":"CONCAT","description":"The CONCAT function in SQL concatenates two or more strings into one string.","sidebar":"autoSidebar"},"sql-syntax/functions/text/concat-ws":{"id":"sql-syntax/functions/text/concat-ws","title":"CONCAT_WS","description":"The CONCAT_WS function in SQL concatenates two or more strings into one string with a separator.","sidebar":"autoSidebar"},"sql-syntax/functions/text/find-idx":{"id":"sql-syntax/functions/text/find-idx","title":"FIND_IDX","description":"The FIND_IDX function in SQL is used to return the position of the first occurrence of a substring in a string, optionally after a specified position.","sidebar":"autoSidebar"},"sql-syntax/functions/text/initcap":{"id":"sql-syntax/functions/text/initcap","title":"INITCAP","description":"The INITCAP function in SQL is used to capitalize the first letter of each word in a string and convert the rest of the characters to lowercase.","sidebar":"autoSidebar"},"sql-syntax/functions/text/left":{"id":"sql-syntax/functions/text/left","title":"LEFT","description":"The LEFT function in SQL returns the specified number of characters from the start (left side) of a given string.","sidebar":"autoSidebar"},"sql-syntax/functions/text/lower":{"id":"sql-syntax/functions/text/lower","title":"LOWER","description":"The LOWER function in SQL returns a string in which all alphabetic characters in a specified string are converted to lowercase.","sidebar":"autoSidebar"},"sql-syntax/functions/text/lpad":{"id":"sql-syntax/functions/text/lpad","title":"LPAD","description":"The LPAD function in SQL pads the left side of a string with a specific set of characters.","sidebar":"autoSidebar"},"sql-syntax/functions/text/ltrim":{"id":"sql-syntax/functions/text/ltrim","title":"LTRIM","description":"The LTRIM function in SQL removes characters from the left (leading side) of a string.","sidebar":"autoSidebar"},"sql-syntax/functions/text/position":{"id":"sql-syntax/functions/text/position","title":"POSITION","description":"The POSITION function in SQL is used to find the position of a substring in a string. The position of the first occurrence of the substring is returned. If the substring is not found, this function returns 0.","sidebar":"autoSidebar"},"sql-syntax/functions/text/repeat":{"id":"sql-syntax/functions/text/repeat","title":"REPEAT","description":"The REPEAT function in SQL is used to repeat a string for a specified number of times.","sidebar":"autoSidebar"},"sql-syntax/functions/text/reverse":{"id":"sql-syntax/functions/text/reverse","title":"REVERSE","description":"The REVERSE function in SQL is used to reverse a string.","sidebar":"autoSidebar"},"sql-syntax/functions/text/right":{"id":"sql-syntax/functions/text/right","title":"RIGHT","description":"The RIGHT function in SQL returns the specified number of characters from the end (right side) of a given string.","sidebar":"autoSidebar"},"sql-syntax/functions/text/rpad":{"id":"sql-syntax/functions/text/rpad","title":"RPAD","description":"The RPAD function in SQL pads the right side of a string with a specific set of characters.","sidebar":"autoSidebar"},"sql-syntax/functions/text/rtrim":{"id":"sql-syntax/functions/text/rtrim","title":"RTRIM","description":"The RTRIM function in SQL removes characters from the right (trailing side) of a string.","sidebar":"autoSidebar"},"sql-syntax/functions/text/substr":{"id":"sql-syntax/functions/text/substr","title":"SUBSTR","description":"The SUBSTR function in SQL is used to extract a substring from a string.","sidebar":"autoSidebar"},"sql-syntax/functions/text/trim":{"id":"sql-syntax/functions/text/trim","title":"TRIM","description":"The TRIM function in SQL is used to remove leading, trailing, or both leading and trailing unwanted characters (often whitespace) from a string.","sidebar":"autoSidebar"},"sql-syntax/functions/text/upper":{"id":"sql-syntax/functions/text/upper","title":"UPPER","description":"The UPPER function in SQL converts all lowercase alphabetic characters in a specified string to uppercase.","sidebar":"autoSidebar"},"sql-syntax/intro":{"id":"sql-syntax/intro","title":"Introduction","description":"Welcome to the Introduction page for the SQL Syntax category in GlueSQL! In this section, we\'ll provide a brief overview of the SQL syntax supported by GlueSQL. You can find more in-depth examples and details by browsing the other pages in this category.","sidebar":"autoSidebar"},"sql-syntax/statements/data-definition/alter-table":{"id":"sql-syntax/statements/data-definition/alter-table","title":"ALTER TABLE","description":"The ALTER TABLE statement is an SQL command used to modify the structure of an existing table in a database. This operation is useful when you need to add, remove, or modify columns or constraints in a table. In this document, we\'ll explain the syntax and usage of the ALTER TABLE statement, including the RENAME, ADD COLUMN, and DROP COLUMN clauses.","sidebar":"autoSidebar"},"sql-syntax/statements/data-definition/create-index":{"id":"sql-syntax/statements/data-definition/create-index","title":"CREATE INDEX","description":"CREATE INDEX statement is used to create an index on one or more columns of a table. Indexes can improve query performance by allowing the database to quickly locate rows with specific column values. They can also be used with the ORDER BY clause to improve sorting performance. An index can be thought of as a data structure that maps the values of a specific column or columns to the corresponding rows in a table. This mapping allows the database to perform lookups and sorting operations more efficiently, as it does not have to scan the entire table.","sidebar":"autoSidebar"},"sql-syntax/statements/data-definition/create-table":{"id":"sql-syntax/statements/data-definition/create-table","title":"CREATE TABLE","description":"The CREATE TABLE statement is a fundamental SQL command used to create a new table in a database. Tables are the primary structure in databases, as they hold the data organized in rows and columns. In this document, we\'ll explain the syntax and usage of the CREATE TABLE statement, including the IF NOT EXISTS clause.","sidebar":"autoSidebar"},"sql-syntax/statements/data-definition/drop-index":{"id":"sql-syntax/statements/data-definition/drop-index","title":"DROP INDEX","description":"DROP INDEX statement is used to remove an existing index from a table. This can be useful when an index is no longer needed, or if you want to free up storage space and reduce maintenance overhead associated with maintaining the index.","sidebar":"autoSidebar"},"sql-syntax/statements/data-definition/drop-table":{"id":"sql-syntax/statements/data-definition/drop-table","title":"DROP TABLE","description":"The DROP TABLE statement is an SQL command used to remove one or more tables from a database. This operation is useful when you no longer need a table or want to clear out old data structures. In this document, we\'ll explain the syntax and usage of the DROP TABLE statement, including the IF EXISTS clause and dropping multiple tables at once.","sidebar":"autoSidebar"},"sql-syntax/statements/data-manipulation/delete":{"id":"sql-syntax/statements/data-manipulation/delete","title":"DELETE","description":"The DELETE statement is used to remove records from a table. You can delete a single row, multiple rows, or all rows at once based on specific conditions.","sidebar":"autoSidebar"},"sql-syntax/statements/data-manipulation/insert":{"id":"sql-syntax/statements/data-manipulation/insert","title":"INSERT","description":"The INSERT statement is used to insert new records into a table. You can insert a single row or multiple rows at once, and you can also use the NULL, NOT NULL, and DEFAULT constraints to define how values are inserted.","sidebar":"autoSidebar"},"sql-syntax/statements/data-manipulation/update":{"id":"sql-syntax/statements/data-manipulation/update","title":"UPDATE","description":"The UPDATE statement is used to modify existing records in a table. You can update one or more columns with new values, or even use subqueries to update values based on other tables.","sidebar":"autoSidebar"},"sql-syntax/statements/metadata/data-dictionary":{"id":"sql-syntax/statements/metadata/data-dictionary","title":"Data Dictionary","description":"In GlueSQL, there are predefined tables, also known as Data Dictionary tables, which store metadata about the database objects like tables, columns, and indexes. These tables can be queried like any other table in the database, and they provide useful information about the database schema.","sidebar":"autoSidebar"},"sql-syntax/statements/metadata/show-tables":{"id":"sql-syntax/statements/metadata/show-tables","title":"SHOW TABLES","description":"The SHOW TABLES statement in GlueSQL is used to display a list of tables available in the database. This statement is useful when you want to inspect the current structure of your database or when you want to manage multiple tables.","sidebar":"autoSidebar"},"sql-syntax/statements/querying/aggregation":{"id":"sql-syntax/statements/querying/aggregation","title":"Aggregation","description":"GlueSQL supports several aggregate functions to perform calculations on a set of values. Below is a list of supported aggregate functions along with a brief explanation of each:","sidebar":"autoSidebar"},"sql-syntax/statements/querying/join":{"id":"sql-syntax/statements/querying/join","title":"JOIN","description":"GlueSQL supports two types of JOIN operations:","sidebar":"autoSidebar"},"sql-syntax/statements/querying/limit":{"id":"sql-syntax/statements/querying/limit","title":"LIMIT & OFFSET","description":"LIMIT and OFFSET are SQL clauses that allow you to control the number of rows returned by a SELECT statement. They are particularly useful when you need to paginate or retrieve a specific portion of the result set.","sidebar":"autoSidebar"},"sql-syntax/statements/querying/schemaless":{"id":"sql-syntax/statements/querying/schemaless","title":"Schemaless Data","description":"GlueSQL is an SQL database that provides a unique feature: it allows you to work with schemaless data, similar to NoSQL databases. Please note this point in the documentation.","sidebar":"autoSidebar"},"sql-syntax/statements/querying/where":{"id":"sql-syntax/statements/querying/where","title":"WHERE","description":"In GlueSQL, the WHERE clause is used to filter the results of a SELECT query based on specific conditions. The WHERE clause can be used with various operators and functions to create complex filtering conditions.","sidebar":"autoSidebar"},"sql-syntax/statements/transaction":{"id":"sql-syntax/statements/transaction","title":"Transaction","description":"Transactions in SQL are a series of queries that are executed as a single unit of work. In GlueSQL, transactions help to ensure the consistency and integrity of the database. They follow the ACID properties: Atomicity, Consistency, Isolation, and Durability.","sidebar":"autoSidebar"},"storages/developing-custom-storages/intro":{"id":"storages/developing-custom-storages/intro","title":"Introduction","description":"With GlueSQL, you can adapt SQL and the AST Builder to a wide variety of environments. This includes file systems, key-value databases, complex NoSQL databases, and even remote APIs. As long as a system supports reading, it can support SELECT queries. If it supports both reading and writing, it can support most SQL operations, including UPDATE and DELETE.","sidebar":"autoSidebar"},"storages/developing-custom-storages/store-traits/alter-table":{"id":"storages/developing-custom-storages/store-traits/alter-table","title":"AlterTable","description":"The AlterTable trait corresponds to the SQL ALTER TABLE statement and is used for modifying existing schemas. It is not necessary to implement the AlterTable trait. If you are dealing with data that is difficult to modify schema-wise or schemaless data, there is no need to implement the AlterTable trait. It is an optional trait that custom storage developers can choose to implement.","sidebar":"autoSidebar"},"storages/developing-custom-storages/store-traits/custom-function":{"id":"storages/developing-custom-storages/store-traits/custom-function","title":"CustomFunction","description":"The CustomFunction trait is an optional trait for supporting user-level custom functions. Through the CustomFunction trait, you can retrieve custom functions stored in the storage system. You can choose to implement the CustomFunction trait alone or together with the CustomFunctionMut trait.","sidebar":"autoSidebar"},"storages/developing-custom-storages/store-traits/custom-function-mut":{"id":"storages/developing-custom-storages/store-traits/custom-function-mut","title":"CustomFunctionMut","description":"By implementing both the CustomFunction and CustomFunctionMut traits, users can create, use, and delete user-level custom functions. Although GlueSQL plans to continuously add various functions, users may still find them insufficient. In such cases, users can create their own user-level custom functions to supplement the built-in functions. Additionally, if there are repetitive business logic codes, they can be stored as custom functions.","sidebar":"autoSidebar"},"storages/developing-custom-storages/store-traits/index-mut":{"id":"storages/developing-custom-storages/store-traits/index-mut","title":"IndexMut","description":"The IndexMut trait, when implemented along with the Index trait, allows custom storage developers to provide users with the ability to create, use, and delete non-clustered indexes. Implementing the IndexMut trait enhances the storage system\'s capabilities by providing support for dynamic index management.","sidebar":"autoSidebar"},"storages/developing-custom-storages/store-traits/index-trait":{"id":"storages/developing-custom-storages/store-traits/index-trait","title":"Index","description":"The Index trait is designed to support non-clustered indexes. If you only need to support pre-built non-clustered indexes, implementing the Index trait without the IndexMut trait is sufficient. Note that clustered indexes (PRIMARY KEY) are automatically supported by the Store & StoreMut implementations. The Index trait is specifically for non-clustered index support.","sidebar":"autoSidebar"},"storages/developing-custom-storages/store-traits/metadata":{"id":"storages/developing-custom-storages/store-traits/metadata","title":"Metadata","description":"The Metadata trait is an optional implementation for providing additional metadata support in GlueSQL. GlueSQL does not enforce any specific metadata implementation, allowing custom storage developers to decide which type of metadata, such as create time, modify time, etc., they want to provide.","sidebar":"autoSidebar"},"storages/developing-custom-storages/store-traits/store":{"id":"storages/developing-custom-storages/store-traits/store","title":"Store","description":"The Store trait is the most essential trait to implement for custom storage. Simply by implementing the Store trait, you can support SELECT queries in SQL. You may want to analyze and retrieve data from log files or external APIs using SQL. In this case, having only SELECT queries available is sufficient, and there might not be any need for data modification. In such scenarios, implementing GlueSQL\'s Store trait alone would be adequate.","sidebar":"autoSidebar"},"storages/developing-custom-storages/store-traits/store-mut":{"id":"storages/developing-custom-storages/store-traits/store-mut","title":"StoreMut","description":"While the Store trait is for supporting SELECT queries and reading data, the StoreMut trait is for modifying data. Implementing the StoreMut trait requires the implementation of the Store trait as well. By implementing both the Store and StoreMut traits, you can support most of the commonly used SQL statements. Additionally, you can use the Test Suite to utilize the integration test set provided by GlueSQL. Custom storage developers can verify their own Store & StoreMut implementations by checking if they pass all the tests provided in the Test Suite.","sidebar":"autoSidebar"},"storages/developing-custom-storages/store-traits/transaction":{"id":"storages/developing-custom-storages/store-traits/transaction","title":"Transaction","description":"While transactions are often considered an essential feature for databases, GlueSQL treats transactions as an optional trait. Custom storage developers can choose whether or not to support transactions in their storage implementation. Transactions can be quite heavy and expensive in terms of performance.","sidebar":"autoSidebar"},"storages/developing-custom-storages/using-test-suite":{"id":"storages/developing-custom-storages/using-test-suite","title":"Using the Test Suite","description":"The GlueSQL Test Suite is a valuable tool for validating your custom storage implementation. By using the provided test sets, you can ensure that your storage implementation adheres to the required specifications and works as expected with GlueSQL.","sidebar":"autoSidebar"},"storages/intro":{"id":"storages/intro","title":"Introduction","description":"GlueSQL is not only suitable for use as a conventional database, but one of its key features is the ability for anyone to easily adapt SQL and the AST Builder to their desired file or storage system. This adaptability is achieved through the following topics covered in this section:","sidebar":"autoSidebar"},"storages/supported-storages/composite-storage":{"id":"storages/supported-storages/composite-storage","title":"Composite Storage","description":"Introduction","sidebar":"autoSidebar"},"storages/supported-storages/csv-storage":{"id":"storages/supported-storages/csv-storage","title":"CSV Storage","description":"Introducing CSVStorage: a utility to process *.csv files, enabling SQL-like query operations such as SELECT, INSERT, and UPDATE.","sidebar":"autoSidebar"},"storages/supported-storages/idb-storage":{"id":"storages/supported-storages/idb-storage","title":"IndexedDB Storage","description":"Introduction","sidebar":"autoSidebar"},"storages/supported-storages/json-storage":{"id":"storages/supported-storages/json-storage","title":"JSON Storage","description":"Introduction","sidebar":"autoSidebar"},"storages/supported-storages/memory-storage":{"id":"storages/supported-storages/memory-storage","title":"Memory Storage","description":"MemoryStorage is a foundational storage option designed for in-memory, non-persistent data. Despite its simplicity, it is robust enough for use in production environments.","sidebar":"autoSidebar"},"storages/supported-storages/parquet-storage":{"id":"storages/supported-storages/parquet-storage","title":"Parquet Storage","description":"Introduction","sidebar":"autoSidebar"},"storages/supported-storages/shared-memory-storage":{"id":"storages/supported-storages/shared-memory-storage","title":"Shared Memory Storage","description":"SharedMemoryStorage is a storage option designed to provide more comfortable usage of MemoryStorage in concurrent environments. Although it doesn\'t operate in parallel, it makes accessing the same data from multiple threads simultaneously more convenient.","sidebar":"autoSidebar"},"storages/supported-storages/sled-storage":{"id":"storages/supported-storages/sled-storage","title":"Sled Storage","description":"SledStorage is currently the representative persistent data storage for GlueSQL. As the name suggests, it\'s a storage option based on the Sled key-value embedded database built in Rust (Sled on Github).","sidebar":"autoSidebar"},"storages/supported-storages/web-storage":{"id":"storages/supported-storages/web-storage","title":"WebStorage (local & session)","description":"WebStorage - yes, the localStorage and sessionStorage you\'re familiar with. With GlueSQL, you can use SQL to interact with these storages!","sidebar":"autoSidebar"}}}')}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/952dfacb.b6458afa.js b/docs/0.16.0/assets/js/952dfacb.b6458afa.js new file mode 100644 index 00000000..6175f637 --- /dev/null +++ b/docs/0.16.0/assets/js/952dfacb.b6458afa.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[6571],{5680:(e,t,r)=>{r.d(t,{xA:()=>u,yg:()=>y});var n=r(6540);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?a(Object(r),!0).forEach((function(t){o(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):a(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function s(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},a=Object.keys(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=n.createContext({}),d=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},u=function(e){var t=d(e.components);return n.createElement(l.Provider,{value:t},e.children)},c="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},g=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),c=d(r),g=o,y=c["".concat(l,".").concat(g)]||c[g]||p[g]||a;return r?n.createElement(y,i(i({ref:t},u),{},{components:r})):n.createElement(y,i({ref:t},u))}));function y(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,i=new Array(a);i[0]=g;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[c]="string"==typeof e?e:o,i[1]=s;for(var d=2;d<a;d++)i[d]=r[d];return n.createElement.apply(null,i)}return n.createElement.apply(null,r)}g.displayName="MDXCreateElement"},4552:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>p,frontMatter:()=>a,metadata:()=>s,toc:()=>d});var n=r(8168),o=(r(6540),r(5680));const a={},i="IndexedDB Storage",s={unversionedId:"storages/supported-storages/idb-storage",id:"storages/supported-storages/idb-storage",title:"IndexedDB Storage",description:"Introduction",source:"@site/docs/storages/supported-storages/idb-storage.md",sourceDirName:"storages/supported-storages",slug:"/storages/supported-storages/idb-storage",permalink:"/docs/0.16.0/storages/supported-storages/idb-storage",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"CSV Storage",permalink:"/docs/0.16.0/storages/supported-storages/csv-storage"},next:{title:"JSON Storage",permalink:"/docs/0.16.0/storages/supported-storages/json-storage"}},l={},d=[{value:"Introduction",id:"introduction",level:2},{value:"Behind the Scenes",id:"behind-the-scenes",level:2},{value:"Compatibility and Use",id:"compatibility-and-use",level:2},{value:"Summary",id:"summary",level:2}],u={toc:d},c="wrapper";function p(e){let{components:t,...r}=e;return(0,o.yg)(c,(0,n.A)({},u,r,{components:t,mdxType:"MDXLayout"}),(0,o.yg)("h1",{id:"indexeddb-storage"},"IndexedDB Storage"),(0,o.yg)("h2",{id:"introduction"},"Introduction"),(0,o.yg)("p",null,"IndexedDB, now easily handled just like SQL with GlueSQL - this is truly magical! For those who have directly used IndexedDB before, it's well known that it's not the most intuitive type of database to interact with. Even the ",(0,o.yg)("a",{parentName:"p",href:"https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API"},"MDN IndexedDB introduction page")," acknowledges this complexity, stating:"),(0,o.yg)("blockquote",null,(0,o.yg)("p",{parentName:"blockquote"},"Note: IndexedDB API is powerful, but may seem too complicated for simple cases. If you'd prefer a simple API, try libraries in See also section that make IndexedDB more programmer-friendly.")),(0,o.yg)("p",null,"In particular, version management in IndexedDB might be a somewhat unfamiliar concept for regular database users. But worry not, GlueSQL has innovatively handled these intricacies, freeing you from the need to grapple with such complexities. You can just use SQL, and everything will work as expected."),(0,o.yg)("h2",{id:"behind-the-scenes"},"Behind the Scenes"),(0,o.yg)("p",null,"When there are schema changes, like a CREATE TABLE query, GlueSQL increases the IndexedDB version and handles it internally. The data to be stored is also converted into a JSON format for storage. Thanks to this, you can easily check how GlueSQL is handling data by using the IndexedDB viewer in the web browser's developer console."),(0,o.yg)("h2",{id:"compatibility-and-use"},"Compatibility and Use"),(0,o.yg)("p",null,"Currently, only the ",(0,o.yg)("inlineCode",{parentName:"p"},"Store")," and ",(0,o.yg)("inlineCode",{parentName:"p"},"StoreMut")," traits are implemented and supported. You can use it in both JavaScript (Web) and Rust WebAssembly environments."),(0,o.yg)("p",null,"When using it in a web environment, just set the ENGINE to indexedDB in the CREATE TABLE query."),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE Item (id INTEGER, name TEXT) ENGINE = indexedDB;\n")),(0,o.yg)("p",null,"Just by using it like this, GlueSQL will operate based on the IndexedDB storage."),(0,o.yg)("h2",{id:"summary"},"Summary"),(0,o.yg)("p",null,"In conclusion, if you are seeking for a way to interact with IndexedDB without the usual complexity, GlueSQL is a fantastic choice. It provides a clear, SQL-based approach to managing data, making IndexedDB much more accessible and user-friendly."))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/97081ee7.4d3ce296.js b/docs/0.16.0/assets/js/97081ee7.4d3ce296.js new file mode 100644 index 00000000..bd46602e --- /dev/null +++ b/docs/0.16.0/assets/js/97081ee7.4d3ce296.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[7033],{5680:(e,t,n)=>{n.d(t,{xA:()=>u,yg:()=>y});var r=n(6540);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?l(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):l(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function o(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},l=Object.keys(e);for(r=0;r<l.length;r++)n=l[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(r=0;r<l.length;r++)n=l[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),p=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},u=function(e){var t=p(e.components);return r.createElement(s.Provider,{value:t},e.children)},c="mdxType",g={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,l=e.originalType,s=e.parentName,u=o(e,["components","mdxType","originalType","parentName"]),c=p(n),d=a,y=c["".concat(s,".").concat(d)]||c[d]||g[d]||l;return n?r.createElement(y,i(i({ref:t},u),{},{components:n})):r.createElement(y,i({ref:t},u))}));function y(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var l=n.length,i=new Array(l);i[0]=d;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[c]="string"==typeof e?e:a,i[1]=o;for(var p=2;p<l;p++)i[p]=n[p];return r.createElement.apply(null,i)}return r.createElement.apply(null,n)}d.displayName="MDXCreateElement"},5316:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>g,frontMatter:()=>l,metadata:()=>o,toc:()=>p});var r=n(8168),a=(n(6540),n(5680));const l={},i="LPAD",o={unversionedId:"sql-syntax/functions/text/lpad",id:"sql-syntax/functions/text/lpad",title:"LPAD",description:"The LPAD function in SQL pads the left side of a string with a specific set of characters.",source:"@site/docs/sql-syntax/functions/text/lpad.md",sourceDirName:"sql-syntax/functions/text",slug:"/sql-syntax/functions/text/lpad",permalink:"/docs/0.16.0/sql-syntax/functions/text/lpad",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"LOWER",permalink:"/docs/0.16.0/sql-syntax/functions/text/lower"},next:{title:"LTRIM",permalink:"/docs/0.16.0/sql-syntax/functions/text/ltrim"}},s={},p=[{value:"Syntax",id:"syntax",level:2},{value:"Parameters",id:"parameters",level:2},{value:"Return Value",id:"return-value",level:2},{value:"Errors",id:"errors",level:2},{value:"Examples",id:"examples",level:2}],u={toc:p},c="wrapper";function g(e){let{components:t,...n}=e;return(0,a.yg)(c,(0,r.A)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"lpad"},"LPAD"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"LPAD")," function in SQL pads the left side of a string with a specific set of characters."),(0,a.yg)("h2",{id:"syntax"},"Syntax"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"LPAD(string, length, pad_string)\n")),(0,a.yg)("h2",{id:"parameters"},"Parameters"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"string"),": The original string to pad."),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"length"),": The length of the resulting string after padding. If this is less than the length of the original string, the result is truncated."),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"pad_string")," (optional): The string to use for padding. If not supplied, spaces are used.")),(0,a.yg)("h2",{id:"return-value"},"Return Value"),(0,a.yg)("p",null,"The function returns a new string that is the same as the original string, but with additional padding on the left side to achieve the specified length."),(0,a.yg)("h2",{id:"errors"},"Errors"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},"If the ",(0,a.yg)("inlineCode",{parentName:"li"},"string")," argument is not a string, a ",(0,a.yg)("inlineCode",{parentName:"li"},"FunctionRequiresStringValue")," error will be returned."),(0,a.yg)("li",{parentName:"ul"},"If the ",(0,a.yg)("inlineCode",{parentName:"li"},"length")," argument is not a positive integer, a ",(0,a.yg)("inlineCode",{parentName:"li"},"FunctionRequiresUSizeValue")," error will be returned.")),(0,a.yg)("h2",{id:"examples"},"Examples"),(0,a.yg)("p",null,"Consider a table ",(0,a.yg)("inlineCode",{parentName:"p"},"Item")," created and filled with the following data:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE Item (\n name TEXT\n);\nINSERT INTO Item VALUES ('hello');\n")),(0,a.yg)("p",null,"You can use the ",(0,a.yg)("inlineCode",{parentName:"p"},"LPAD")," function to pad the ",(0,a.yg)("inlineCode",{parentName:"p"},"name")," values to a length of 10 with the character 'a':"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT LPAD(name, 10, 'a') AS padded_name FROM Item;\n")),(0,a.yg)("p",null,"This will return:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre"},"aaaaahello\n")),(0,a.yg)("p",null,"If the ",(0,a.yg)("inlineCode",{parentName:"p"},"length")," argument is less than the length of the string, the original string will be truncated:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT LPAD(name, 3, 'a') AS padded_name FROM Item;\n")),(0,a.yg)("p",null,"This will return:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre"},"hel\n")))}g.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/980f8d5e.0a236b42.js b/docs/0.16.0/assets/js/980f8d5e.0a236b42.js new file mode 100644 index 00000000..f88c9e52 --- /dev/null +++ b/docs/0.16.0/assets/js/980f8d5e.0a236b42.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[4848],{5680:(e,t,n)=>{n.d(t,{xA:()=>s,yg:()=>f});var r=n(6540);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?a(Object(n),!0).forEach((function(t){o(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):a(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function c(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},a=Object.keys(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var l=r.createContext({}),u=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},s=function(e){var t=u(e.components);return r.createElement(l.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,s=c(e,["components","mdxType","originalType","parentName"]),p=u(n),m=o,f=p["".concat(l,".").concat(m)]||p[m]||d[m]||a;return n?r.createElement(f,i(i({ref:t},s),{},{components:n})):r.createElement(f,i({ref:t},s))}));function f(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,i=new Array(a);i[0]=m;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c[p]="string"==typeof e?e:o,i[1]=c;for(var u=2;u<a;u++)i[u]=n[u];return r.createElement.apply(null,i)}return r.createElement.apply(null,n)}m.displayName="MDXCreateElement"},7605:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>d,frontMatter:()=>a,metadata:()=>c,toc:()=>u});var r=n(8168),o=(n(6540),n(5680));const a={},i="Logarithmic and Exponential",c={unversionedId:"ast-builder/functions/math/logarithmic-and-exponential",id:"ast-builder/functions/math/logarithmic-and-exponential",title:"Logarithmic and Exponential",description:"Todo",source:"@site/docs/ast-builder/functions/math/logarithmic-and-exponential.md",sourceDirName:"ast-builder/functions/math",slug:"/ast-builder/functions/math/logarithmic-and-exponential",permalink:"/docs/0.16.0/ast-builder/functions/math/logarithmic-and-exponential",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"Conversion",permalink:"/docs/0.16.0/ast-builder/functions/math/conversion"},next:{title:"Rounding",permalink:"/docs/0.16.0/ast-builder/functions/math/rounding"}},l={},u=[{value:"Todo",id:"todo",level:2}],s={toc:u},p="wrapper";function d(e){let{components:t,...n}=e;return(0,o.yg)(p,(0,r.A)({},s,n,{components:t,mdxType:"MDXLayout"}),(0,o.yg)("h1",{id:"logarithmic-and-exponential"},"Logarithmic and Exponential"),(0,o.yg)("h2",{id:"todo"},"Todo"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre"},"- EXP: Returns e raised to the power of a specified number.\n- LN: Returns the natural logarithm of a number.\n- LOG: Returns the logarithm of a number to a specified base.\n- LOG10: Returns the base-10 logarithm of a number.\n- LOG2: Returns the base-2 logarithm of a number.\n- POWER: Raises a number to the power of another number.\n")))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/98184455.9f967dd2.js b/docs/0.16.0/assets/js/98184455.9f967dd2.js new file mode 100644 index 00000000..8f9a8561 --- /dev/null +++ b/docs/0.16.0/assets/js/98184455.9f967dd2.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[4541],{8419:o=>{o.exports=JSON.parse('{"permalink":"/docs/0.16.0/blog/tags/proposal","page":1,"postsPerPage":10,"totalPages":1,"totalCount":1,"blogDescription":"Blog","blogTitle":"Blog"}')}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/98306a23.b1ce97fe.js b/docs/0.16.0/assets/js/98306a23.b1ce97fe.js new file mode 100644 index 00000000..548e5bf7 --- /dev/null +++ b/docs/0.16.0/assets/js/98306a23.b1ce97fe.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[5535],{5680:(e,t,n)=>{n.d(t,{xA:()=>u,yg:()=>y});var a=n(6540);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function l(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function o(e,t){if(null==e)return{};var n,a,r=function(e,t){if(null==e)return{};var n,a,r={},i=Object.keys(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=a.createContext({}),c=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},u=function(e){var t=c(e.components);return a.createElement(s.Provider,{value:t},e.children)},m="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,u=o(e,["components","mdxType","originalType","parentName"]),m=c(n),d=r,y=m["".concat(s,".").concat(d)]||m[d]||p[d]||i;return n?a.createElement(y,l(l({ref:t},u),{},{components:n})):a.createElement(y,l({ref:t},u))}));function y(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,l=new Array(i);l[0]=d;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[m]="string"==typeof e?e:r,l[1]=o;for(var c=2;c<i;c++)l[c]=n[c];return a.createElement.apply(null,l)}return a.createElement.apply(null,n)}d.displayName="MDXCreateElement"},7835:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>p,frontMatter:()=>i,metadata:()=>o,toc:()=>c});var a=n(8168),r=(n(6540),n(5680));const i={},l="NOW",o={unversionedId:"sql-syntax/functions/datetime/now",id:"sql-syntax/functions/datetime/now",title:"NOW",description:"The NOW() function in SQL returns the current date and time in UTC. You can use it to retrieve the current UTC timestamp, or as a default value for a TIMESTAMP column in a table.",source:"@site/docs/sql-syntax/functions/datetime/now.md",sourceDirName:"sql-syntax/functions/datetime",slug:"/sql-syntax/functions/datetime/now",permalink:"/docs/0.16.0/sql-syntax/functions/datetime/now",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"FORMAT",permalink:"/docs/0.16.0/sql-syntax/functions/datetime/format"},next:{title:"TO_DATE",permalink:"/docs/0.16.0/sql-syntax/functions/datetime/to-date"}},s={},c=[{value:"Syntax",id:"syntax",level:2},{value:"Examples",id:"examples",level:2},{value:"Creating a table with a TIMESTAMP column and setting the default value to NOW()",id:"creating-a-table-with-a-timestamp-column-and-setting-the-default-value-to-now",level:3},{value:"Inserting data into the table",id:"inserting-data-into-the-table",level:3},{value:"Selecting rows where the timestamp is greater than the current timestamp",id:"selecting-rows-where-the-timestamp-is-greater-than-the-current-timestamp",level:3}],u={toc:c},m="wrapper";function p(e){let{components:t,...n}=e;return(0,r.yg)(m,(0,a.A)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,r.yg)("h1",{id:"now"},"NOW"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"NOW()")," function in SQL returns the current date and time in UTC. You can use it to retrieve the current UTC timestamp, or as a default value for a TIMESTAMP column in a table. "),(0,r.yg)("h2",{id:"syntax"},"Syntax"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre"},"NOW()\n")),(0,r.yg)("h2",{id:"examples"},"Examples"),(0,r.yg)("h3",{id:"creating-a-table-with-a-timestamp-column-and-setting-the-default-value-to-now"},"Creating a table with a TIMESTAMP column and setting the default value to NOW()"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE Item (time TIMESTAMP DEFAULT NOW());\n")),(0,r.yg)("p",null,"This creates a table named ",(0,r.yg)("inlineCode",{parentName:"p"},"Item")," with a column ",(0,r.yg)("inlineCode",{parentName:"p"},"time")," of the type TIMESTAMP. The default value for this column is the current UTC timestamp."),(0,r.yg)("h3",{id:"inserting-data-into-the-table"},"Inserting data into the table"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO Item (time) VALUES\n ('2021-10-13T06:42:40.364832862'),\n ('9999-12-31T23:59:40.364832862');\n")),(0,r.yg)("p",null,"Here we're inserting two rows into the ",(0,r.yg)("inlineCode",{parentName:"p"},"Item")," table with specific timestamps."),(0,r.yg)("h3",{id:"selecting-rows-where-the-timestamp-is-greater-than-the-current-timestamp"},"Selecting rows where the timestamp is greater than the current timestamp"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT time FROM Item WHERE time > NOW();\n")),(0,r.yg)("p",null,"This query selects the ",(0,r.yg)("inlineCode",{parentName:"p"},"time")," column from the ",(0,r.yg)("inlineCode",{parentName:"p"},"Item")," table where the ",(0,r.yg)("inlineCode",{parentName:"p"},"time")," is greater than the current UTC timestamp. In this case, the result will be:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre"},"9999-12-31T23:59:40.364832862\n")))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/9a1c8bc6.dce511c1.js b/docs/0.16.0/assets/js/9a1c8bc6.dce511c1.js new file mode 100644 index 00000000..98a01f34 --- /dev/null +++ b/docs/0.16.0/assets/js/9a1c8bc6.dce511c1.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[5760],{5680:(e,n,t)=>{t.d(n,{xA:()=>p,yg:()=>y});var a=t(6540);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function l(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function i(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?l(Object(t),!0).forEach((function(n){r(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):l(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function s(e,n){if(null==e)return{};var t,a,r=function(e,n){if(null==e)return{};var t,a,r={},l=Object.keys(e);for(a=0;a<l.length;a++)t=l[a],n.indexOf(t)>=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a<l.length;a++)t=l[a],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var u=a.createContext({}),o=function(e){var n=a.useContext(u),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},p=function(e){var n=o(e.components);return a.createElement(u.Provider,{value:n},e.children)},c="mdxType",g={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},m=a.forwardRef((function(e,n){var t=e.components,r=e.mdxType,l=e.originalType,u=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),c=o(t),m=r,y=c["".concat(u,".").concat(m)]||c[m]||g[m]||l;return t?a.createElement(y,i(i({ref:n},p),{},{components:t})):a.createElement(y,i({ref:n},p))}));function y(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var l=t.length,i=new Array(l);i[0]=m;var s={};for(var u in n)hasOwnProperty.call(n,u)&&(s[u]=n[u]);s.originalType=e,s[c]="string"==typeof e?e:r,i[1]=s;for(var o=2;o<l;o++)i[o]=t[o];return a.createElement.apply(null,i)}return a.createElement.apply(null,t)}m.displayName="MDXCreateElement"},4414:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>u,contentTitle:()=>i,default:()=>g,frontMatter:()=>l,metadata:()=>s,toc:()=>o});var a=t(8168),r=(t(6540),t(5680));const l={},i="SIN",s={unversionedId:"sql-syntax/functions/math/sin",id:"sql-syntax/functions/math/sin",title:"SIN",description:"The SIN function is used to calculate the sine of a number. It takes a single numeric argument (angle in radians) and returns the sine of that angle.",source:"@site/docs/sql-syntax/functions/math/sin.md",sourceDirName:"sql-syntax/functions/math",slug:"/sql-syntax/functions/math/sin",permalink:"/docs/0.16.0/sql-syntax/functions/math/sin",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"SIGN",permalink:"/docs/0.16.0/sql-syntax/functions/math/sign"},next:{title:"SQRT",permalink:"/docs/0.16.0/sql-syntax/functions/math/sqrt"}},u={},o=[{value:"Syntax",id:"syntax",level:2},{value:"Examples",id:"examples",level:2},{value:"Example 1: Using SIN with float values",id:"example-1-using-sin-with-float-values",level:3},{value:"Example 2: Using SIN with NULL values",id:"example-2-using-sin-with-null-values",level:3},{value:"Errors",id:"errors",level:2},{value:"Example 3: Using SIN with non-numeric values",id:"example-3-using-sin-with-non-numeric-values",level:3},{value:"Example 4: Using SIN with multiple arguments",id:"example-4-using-sin-with-multiple-arguments",level:3}],p={toc:o},c="wrapper";function g(e){let{components:n,...t}=e;return(0,r.yg)(c,(0,a.A)({},p,t,{components:n,mdxType:"MDXLayout"}),(0,r.yg)("h1",{id:"sin"},"SIN"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"SIN")," function is used to calculate the sine of a number. It takes a single numeric argument (angle in radians) and returns the sine of that angle."),(0,r.yg)("h2",{id:"syntax"},"Syntax"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SIN(value)\n")),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"value"),": A numeric expression (angle in radians) for which the sine is to be calculated.")),(0,r.yg)("h2",{id:"examples"},"Examples"),(0,r.yg)("p",null,"Let's consider a table named ",(0,r.yg)("inlineCode",{parentName:"p"},"SingleItem")," with the following schema:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE SingleItem (id INTEGER);\n")),(0,r.yg)("p",null,"Insert a row into the ",(0,r.yg)("inlineCode",{parentName:"p"},"SingleItem")," table:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO SingleItem VALUES (0);\n")),(0,r.yg)("h3",{id:"example-1-using-sin-with-float-values"},"Example 1: Using SIN with float values"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT SIN(0.5) AS sin1, SIN(1) AS sin2 FROM SingleItem;\n")),(0,r.yg)("p",null,"Result:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre"}," sin1 | sin2\n-------------+--------------\n 0.479425539 | 0.841470984\n")),(0,r.yg)("h3",{id:"example-2-using-sin-with-null-values"},"Example 2: Using SIN with NULL values"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT SIN(NULL) AS sin FROM SingleItem;\n")),(0,r.yg)("p",null,"Result:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre"}," sin\n-------\n (null)\n")),(0,r.yg)("h2",{id:"errors"},"Errors"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"SIN")," function requires a numeric value as its argument. Using non-numeric values or more than one argument will result in an error."),(0,r.yg)("h3",{id:"example-3-using-sin-with-non-numeric-values"},"Example 3: Using SIN with non-numeric values"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT SIN('string') AS sin FROM SingleItem;\n")),(0,r.yg)("p",null,"Error: Function requires a numeric value."),(0,r.yg)("h3",{id:"example-4-using-sin-with-multiple-arguments"},"Example 4: Using SIN with multiple arguments"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT SIN(1.0, 2.0) AS sin FROM SingleItem;\n")),(0,r.yg)("p",null,"Error: Function expects 1 argument, but 2 were provided."))}g.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/9a3e57da.6cf35ab2.js b/docs/0.16.0/assets/js/9a3e57da.6cf35ab2.js new file mode 100644 index 00000000..74ab66f2 --- /dev/null +++ b/docs/0.16.0/assets/js/9a3e57da.6cf35ab2.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[3216],{5680:(e,t,n)=>{n.d(t,{xA:()=>u,yg:()=>m});var a=n(6540);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function l(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function i(e,t){if(null==e)return{};var n,a,r=function(e,t){if(null==e)return{};var n,a,r={},o=Object.keys(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var p=a.createContext({}),g=function(e){var t=a.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},u=function(e){var t=g(e.components);return a.createElement(p.Provider,{value:t},e.children)},s="mdxType",y={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},c=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,p=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),s=g(n),c=r,m=s["".concat(p,".").concat(c)]||s[c]||y[c]||o;return n?a.createElement(m,l(l({ref:t},u),{},{components:n})):a.createElement(m,l({ref:t},u))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,l=new Array(o);l[0]=c;var i={};for(var p in t)hasOwnProperty.call(t,p)&&(i[p]=t[p]);i.originalType=e,i[s]="string"==typeof e?e:r,l[1]=i;for(var g=2;g<o;g++)l[g]=n[g];return a.createElement.apply(null,l)}return a.createElement.apply(null,n)}c.displayName="MDXCreateElement"},5887:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>l,default:()=>y,frontMatter:()=>o,metadata:()=>i,toc:()=>g});var a=n(8168),r=(n(6540),n(5680));const o={},l="GET_X",i={unversionedId:"sql-syntax/functions/geometry/get-x",id:"sql-syntax/functions/geometry/get-x",title:"GET_X",description:"The GET_X function returns the x-coordinate of a given POINT data type. It takes one POINT data type argument and returns a FLOAT value representing the x-coordinate.",source:"@site/docs/sql-syntax/functions/geometry/get-x.md",sourceDirName:"sql-syntax/functions/geometry",slug:"/sql-syntax/functions/geometry/get-x",permalink:"/docs/0.16.0/sql-syntax/functions/geometry/get-x",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"CALC_DISTANCE",permalink:"/docs/0.16.0/sql-syntax/functions/geometry/calc-distance"},next:{title:"GET_Y",permalink:"/docs/0.16.0/sql-syntax/functions/geometry/get-y"}},p={},g=[{value:"Syntax",id:"syntax",level:2},{value:"Examples",id:"examples",level:2},{value:"Example 1: Get the X-coordinate from a point",id:"example-1-get-the-x-coordinate-from-a-point",level:3},{value:"Example 2: Get the X-coordinate from a point using CAST",id:"example-2-get-the-x-coordinate-from-a-point-using-cast",level:3},{value:"Example 3: Get the X-coordinate from a point using POINT function",id:"example-3-get-the-x-coordinate-from-a-point-using-point-function",level:3},{value:"Errors",id:"errors",level:2}],u={toc:g},s="wrapper";function y(e){let{components:t,...n}=e;return(0,r.yg)(s,(0,a.A)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,r.yg)("h1",{id:"get_x"},"GET_X"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"GET_X")," function returns the x-coordinate of a given ",(0,r.yg)("inlineCode",{parentName:"p"},"POINT")," data type. It takes one ",(0,r.yg)("inlineCode",{parentName:"p"},"POINT")," data type argument and returns a ",(0,r.yg)("inlineCode",{parentName:"p"},"FLOAT")," value representing the x-coordinate."),(0,r.yg)("h2",{id:"syntax"},"Syntax"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"GET_X(point)\n")),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},"Parameters:")),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"point"),": The geographical coordinate of type ",(0,r.yg)("inlineCode",{parentName:"li"},"Point")," from which the X-coordinate will be extracted.")),(0,r.yg)("h2",{id:"examples"},"Examples"),(0,r.yg)("p",null,"Consider the following table ",(0,r.yg)("inlineCode",{parentName:"p"},"PointGroup"),":"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE PointGroup (\n point_field POINT\n);\n")),(0,r.yg)("p",null,"With the following data:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO PointGroup VALUES (POINT(0.3134, 0.156));\n")),(0,r.yg)("h3",{id:"example-1-get-the-x-coordinate-from-a-point"},"Example 1: Get the X-coordinate from a point"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT GET_X(point_field) AS point_field FROM PointGroup;\n")),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},"Result:")),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},"point_field"))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},"0.3134")))),(0,r.yg)("h3",{id:"example-2-get-the-x-coordinate-from-a-point-using-cast"},"Example 2: Get the X-coordinate from a point using CAST"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT GET_X(CAST('POINT(0.1 -0.2)' AS POINT)) AS ptx;\n")),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},"Result:")),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},"ptx"))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},"0.1")))),(0,r.yg)("h3",{id:"example-3-get-the-x-coordinate-from-a-point-using-point-function"},"Example 3: Get the X-coordinate from a point using POINT function"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT GET_X(POINT(0.1, -0.2)) AS ptx;\n")),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},"Result:")),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},"ptx"))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},"0.1")))),(0,r.yg)("h2",{id:"errors"},"Errors"),(0,r.yg)("p",null,"If the argument is not of type ",(0,r.yg)("inlineCode",{parentName:"p"},"Point"),", a ",(0,r.yg)("inlineCode",{parentName:"p"},"FunctionRequiresPointValue")," error will be thrown."))}y.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/9c5158ac.353fe2b2.js b/docs/0.16.0/assets/js/9c5158ac.353fe2b2.js new file mode 100644 index 00000000..cf838dec --- /dev/null +++ b/docs/0.16.0/assets/js/9c5158ac.353fe2b2.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[6926],{5680:(e,t,n)=>{n.d(t,{xA:()=>s,yg:()=>b});var r=n(6540);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},o=Object.keys(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var u=r.createContext({}),c=function(e){var t=r.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},s=function(e){var t=c(e.components);return r.createElement(u.Provider,{value:t},e.children)},m="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},p=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,u=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),m=c(n),p=a,b=m["".concat(u,".").concat(p)]||m[p]||d[p]||o;return n?r.createElement(b,i(i({ref:t},s),{},{components:n})):r.createElement(b,i({ref:t},s))}));function b(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=p;var l={};for(var u in t)hasOwnProperty.call(t,u)&&(l[u]=t[u]);l.originalType=e,l[m]="string"==typeof e?e:a,i[1]=l;for(var c=2;c<o;c++)i[c]=n[c];return r.createElement.apply(null,i)}return r.createElement.apply(null,n)}p.displayName="MDXCreateElement"},3079:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>u,contentTitle:()=>i,default:()=>d,frontMatter:()=>o,metadata:()=>l,toc:()=>c});var r=n(8168),a=(n(6540),n(5680));const o={},i="Basic Arithmetic",l={unversionedId:"ast-builder/functions/math/basic-arithmetic",id:"ast-builder/functions/math/basic-arithmetic",title:"Basic Arithmetic",description:"GlueSQL provides a number of basic arithmetic operations such as absolute value (abs), division (divide), modulo (modulo), greatest common divisor (gcd), and least common multiple (lcm).",source:"@site/docs/ast-builder/functions/math/basic-arithmetic.md",sourceDirName:"ast-builder/functions/math",slug:"/ast-builder/functions/math/basic-arithmetic",permalink:"/docs/0.16.0/ast-builder/functions/math/basic-arithmetic",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"Trimming",permalink:"/docs/0.16.0/ast-builder/functions/text/trimming"},next:{title:"Conversion",permalink:"/docs/0.16.0/ast-builder/functions/math/conversion"}},u={},c=[{value:"Absolute Value - ABS",id:"absolute-value---abs",level:2},{value:"Division - DIV",id:"division---div",level:2},{value:"Modulo - MOD",id:"modulo---mod",level:2},{value:"Greatest Common Divisor - GCD",id:"greatest-common-divisor---gcd",level:2},{value:"Least Common Multiple - LCM",id:"least-common-multiple---lcm",level:2}],s={toc:c},m="wrapper";function d(e){let{components:t,...n}=e;return(0,a.yg)(m,(0,r.A)({},s,n,{components:t,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"basic-arithmetic"},"Basic Arithmetic"),(0,a.yg)("p",null,"GlueSQL provides a number of basic arithmetic operations such as absolute value (abs), division (divide), modulo (modulo), greatest common divisor (gcd), and least common multiple (lcm)."),(0,a.yg)("p",null,"For this tutorial, we assume there's a table named ",(0,a.yg)("inlineCode",{parentName:"p"},"Number")," with columns ",(0,a.yg)("inlineCode",{parentName:"p"},"id")," and ",(0,a.yg)("inlineCode",{parentName:"p"},"number"),"."),(0,a.yg)("h2",{id:"absolute-value---abs"},"Absolute Value - ABS"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"abs")," function returns the absolute value of a number."),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = values(vec!["0, 0", "1, -3", "2, 4", "3, -29"])\n .alias_as("number")\n .select()\n .project("column1")\n .project(abs("column2")) // Takes the absolute value of column2\n .project(col("column2").abs()) // Takes the absolute value of column2\n .execute(glue)\n .await;\n')),(0,a.yg)("h2",{id:"division---div"},"Division - DIV"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"divide")," function divides one number by another."),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Number")\n .select()\n .project("id")\n .project(divide("number", 3)) // Divides the number by 3\n .project(divide(col("number"), 3)) // Divides the number by 3\n .execute(glue)\n .await;\n')),(0,a.yg)("h2",{id:"modulo---mod"},"Modulo - MOD"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"modulo")," function returns the remainder of one number divided by another."),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Number")\n .select()\n .project("id")\n .project(modulo("number", 4)) // Gets the remainder of number divided by 4\n .project(modulo(col("number"), 4)) // Gets the remainder of number divided by 4\n .execute(glue)\n .await;\n')),(0,a.yg)("h2",{id:"greatest-common-divisor---gcd"},"Greatest Common Divisor - GCD"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"gcd")," function returns the greatest common divisor of two numbers."),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Number")\n .select()\n .project("id")\n .project(gcd("number", 12)) // Gets the GCD of number and 12\n .project(gcd(col("number"), 12)) // Gets the GCD of number and 12\n .execute(glue)\n .await;\n')),(0,a.yg)("h2",{id:"least-common-multiple---lcm"},"Least Common Multiple - LCM"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"lcm")," function returns the least common multiple of two numbers."),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Number")\n .select()\n .project("id")\n .project(lcm("number", 3)) // Gets the LCM of number and 3\n .project(lcm(col("number"), 3)) // Gets the LCM of number and 3\n .execute(glue)\n .await;\n')))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/9c7b888e.0f19b601.js b/docs/0.16.0/assets/js/9c7b888e.0f19b601.js new file mode 100644 index 00000000..affc4df9 --- /dev/null +++ b/docs/0.16.0/assets/js/9c7b888e.0f19b601.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[1489],{3441:s=>{s.exports=JSON.parse('{"permalink":"/docs/0.16.0/blog/tags/database","page":1,"postsPerPage":10,"totalPages":1,"totalCount":3,"blogDescription":"Blog","blogTitle":"Blog"}')}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/9e4087bc.fd7711ba.js b/docs/0.16.0/assets/js/9e4087bc.fd7711ba.js new file mode 100644 index 00000000..c2affdc5 --- /dev/null +++ b/docs/0.16.0/assets/js/9e4087bc.fd7711ba.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[2711],{9331:(e,t,a)=>{a.r(t),a.d(t,{default:()=>o});var r=a(6540),l=a(5489),n=a(1312),c=a(1003),m=a(9408);function s(e){let{year:t,posts:a}=e;return r.createElement(r.Fragment,null,r.createElement("h3",null,t),r.createElement("ul",null,a.map((e=>r.createElement("li",{key:e.metadata.date},r.createElement(l.A,{to:e.metadata.permalink},e.metadata.formattedDate," - ",e.metadata.title))))))}function i(e){let{years:t}=e;return r.createElement("section",{className:"margin-vert--lg"},r.createElement("div",{className:"container"},r.createElement("div",{className:"row"},t.map(((e,t)=>r.createElement("div",{key:t,className:"col col--4 margin-vert--lg"},r.createElement(s,e)))))))}function o(e){let{archive:t}=e;const a=(0,n.T)({id:"theme.blog.archive.title",message:"Archive",description:"The page & hero title of the blog archive page"}),l=(0,n.T)({id:"theme.blog.archive.description",message:"Archive",description:"The page & hero description of the blog archive page"}),s=function(e){const t=e.reduceRight(((e,t)=>{const a=t.metadata.date.split("-")[0],r=e.get(a)??[];return e.set(a,[t,...r])}),new Map);return Array.from(t,(e=>{let[t,a]=e;return{year:t,posts:a}}))}(t.blogPosts);return r.createElement(r.Fragment,null,r.createElement(c.be,{title:a,description:l}),r.createElement(m.A,null,r.createElement("header",{className:"hero hero--primary"},r.createElement("div",{className:"container"},r.createElement("h1",{className:"hero__title"},a),r.createElement("p",{className:"hero__subtitle"},l))),r.createElement("main",null,s.length>0&&r.createElement(i,{years:s}))))}}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/9edb318c.9950535d.js b/docs/0.16.0/assets/js/9edb318c.9950535d.js new file mode 100644 index 00000000..347840b8 --- /dev/null +++ b/docs/0.16.0/assets/js/9edb318c.9950535d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[8032],{8174:e=>{e.exports=JSON.parse('{"permalink":"/docs/0.16.0/blog/tags/test-driven-documentation","page":1,"postsPerPage":10,"totalPages":1,"totalCount":1,"blogDescription":"Blog","blogTitle":"Blog"}')}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/a2ab2bad.24b45834.js b/docs/0.16.0/assets/js/a2ab2bad.24b45834.js new file mode 100644 index 00000000..7432a9b4 --- /dev/null +++ b/docs/0.16.0/assets/js/a2ab2bad.24b45834.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[732],{5680:(e,t,n)=>{n.d(t,{xA:()=>u,yg:()=>m});var r=n(6540);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function a(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){o(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},i=Object.keys(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var c=r.createContext({}),s=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},u=function(e){var t=s(e.components);return r.createElement(c.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},f=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,c=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=s(n),f=o,m=p["".concat(c,".").concat(f)]||p[f]||d[f]||i;return n?r.createElement(m,a(a({ref:t},u),{},{components:n})):r.createElement(m,a({ref:t},u))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,a=new Array(i);a[0]=f;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l[p]="string"==typeof e?e:o,a[1]=l;for(var s=2;s<i;s++)a[s]=n[s];return r.createElement.apply(null,a)}return r.createElement.apply(null,n)}f.displayName="MDXCreateElement"},3184:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>d,frontMatter:()=>i,metadata:()=>l,toc:()=>s});var r=n(8168),o=(n(6540),n(5680));const i={},a="List Manipulation",l={unversionedId:"ast-builder/functions/list-&-map/list-manipulation",id:"ast-builder/functions/list-&-map/list-manipulation",title:"List Manipulation",description:"Todo",source:"@site/docs/ast-builder/functions/list-&-map/list-manipulation.md",sourceDirName:"ast-builder/functions/list-&-map",slug:"/ast-builder/functions/list-&-map/list-manipulation",permalink:"/docs/0.16.0/ast-builder/functions/list-&-map/list-manipulation",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"List and Map Concatenation",permalink:"/docs/0.16.0/ast-builder/functions/list-&-map/list-and-map-concatenation"},next:{title:"Coordinate Extraction",permalink:"/docs/0.16.0/ast-builder/functions/geometry/coordinate-extraction"}},c={},s=[{value:"Todo",id:"todo",level:2}],u={toc:s},p="wrapper";function d(e){let{components:t,...n}=e;return(0,o.yg)(p,(0,r.A)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,o.yg)("h1",{id:"list-manipulation"},"List Manipulation"),(0,o.yg)("h2",{id:"todo"},"Todo"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre"},"- APPEND: Adds an element to the end of a list.\n- PREPEND: Adds an element to the beginning of a list.\n")))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/a470b55c.c5b0f903.js b/docs/0.16.0/assets/js/a470b55c.c5b0f903.js new file mode 100644 index 00000000..117a67dc --- /dev/null +++ b/docs/0.16.0/assets/js/a470b55c.c5b0f903.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[8242],{5680:(e,n,t)=>{t.d(n,{xA:()=>u,yg:()=>m});var r=t(6540);function a(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function o(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function l(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?o(Object(t),!0).forEach((function(n){a(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):o(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function s(e,n){if(null==e)return{};var t,r,a=function(e,n){if(null==e)return{};var t,r,a={},o=Object.keys(e);for(r=0;r<o.length;r++)t=o[r],n.indexOf(t)>=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r<o.length;r++)t=o[r],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var c=r.createContext({}),i=function(e){var n=r.useContext(c),t=n;return e&&(t="function"==typeof e?e(n):l(l({},n),e)),t},u=function(e){var n=i(e.components);return r.createElement(c.Provider,{value:n},e.children)},p="mdxType",y={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},g=r.forwardRef((function(e,n){var t=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=i(t),g=a,m=p["".concat(c,".").concat(g)]||p[g]||y[g]||o;return t?r.createElement(m,l(l({ref:n},u),{},{components:t})):r.createElement(m,l({ref:n},u))}));function m(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var o=t.length,l=new Array(o);l[0]=g;var s={};for(var c in n)hasOwnProperty.call(n,c)&&(s[c]=n[c]);s.originalType=e,s[p]="string"==typeof e?e:a,l[1]=s;for(var i=2;i<o;i++)l[i]=t[i];return r.createElement.apply(null,l)}return r.createElement.apply(null,t)}g.displayName="MDXCreateElement"},5833:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>l,default:()=>y,frontMatter:()=>o,metadata:()=>s,toc:()=>i});var r=t(8168),a=(t(6540),t(5680));const o={},l="CONCAT",s={unversionedId:"sql-syntax/functions/text/concat",id:"sql-syntax/functions/text/concat",title:"CONCAT",description:"The CONCAT function in SQL concatenates two or more strings into one string.",source:"@site/docs/sql-syntax/functions/text/concat.md",sourceDirName:"sql-syntax/functions/text",slug:"/sql-syntax/functions/text/concat",permalink:"/docs/0.16.0/sql-syntax/functions/text/concat",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"CONCAT_WS",permalink:"/docs/0.16.0/sql-syntax/functions/text/concat-ws"},next:{title:"FIND_IDX",permalink:"/docs/0.16.0/sql-syntax/functions/text/find-idx"}},c={},i=[{value:"Syntax",id:"syntax",level:2},{value:"Parameters",id:"parameters",level:2},{value:"Examples",id:"examples",level:2}],u={toc:i},p="wrapper";function y(e){let{components:n,...t}=e;return(0,a.yg)(p,(0,r.A)({},u,t,{components:n,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"concat"},"CONCAT"),(0,a.yg)("p",null,"The CONCAT function in SQL concatenates two or more strings into one string."),(0,a.yg)("h2",{id:"syntax"},"Syntax"),(0,a.yg)("p",null,"The syntax for the CONCAT function in SQL is:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"CONCAT ( string1, string2, ..., stringN )\n")),(0,a.yg)("h2",{id:"parameters"},"Parameters"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"string1"),", ",(0,a.yg)("inlineCode",{parentName:"li"},"string2"),", ..., ",(0,a.yg)("inlineCode",{parentName:"li"},"stringN"),": These are the strings that you wish to concatenate together. ")),(0,a.yg)("h2",{id:"examples"},"Examples"),(0,a.yg)("p",null,"Let's consider a few examples to understand how to use the CONCAT function."),(0,a.yg)("p",null,"To concatenate two strings:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT CONCAT('ab', 'cd') AS myconcat;\n")),(0,a.yg)("p",null,"This will return ",(0,a.yg)("inlineCode",{parentName:"p"},"'abcd'"),"."),(0,a.yg)("p",null,"You can also concatenate more than two strings:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT CONCAT('ab', 'cd', 'ef') AS myconcat;\n")),(0,a.yg)("p",null,"This will return ",(0,a.yg)("inlineCode",{parentName:"p"},"'abcdef'"),"."),(0,a.yg)("p",null,"If any string in the CONCAT function is NULL, the function will return NULL:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT CONCAT('ab', 'cd', NULL, 'ef') AS myconcat;\n")),(0,a.yg)("p",null,"This will return NULL."),(0,a.yg)("p",null,"The CONCAT function can also take non-string arguments:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT CONCAT(123, 456, 3.14) AS myconcat;\n")),(0,a.yg)("p",null,"This will return ",(0,a.yg)("inlineCode",{parentName:"p"},"'1234563.14'"),". In this case, the integers and float values are implicitly converted to strings before concatenation."),(0,a.yg)("p",null,"However, the CONCAT function expects at least one argument. If no arguments are passed to the CONCAT function, it will throw an error:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT CONCAT() AS myconcat;\n")),(0,a.yg)("p",null,"This will throw an error because the CONCAT function expects at least one argument."))}y.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/a4bc1622.56c7a466.js b/docs/0.16.0/assets/js/a4bc1622.56c7a466.js new file mode 100644 index 00000000..503d93a8 --- /dev/null +++ b/docs/0.16.0/assets/js/a4bc1622.56c7a466.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[1656],{5680:(e,t,r)=>{r.d(t,{xA:()=>p,yg:()=>y});var n=r(6540);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function a(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?i(Object(r),!0).forEach((function(t){o(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):i(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function s(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var c=n.createContext({}),l=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},p=function(e){var t=l(e.components);return n.createElement(c.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},f=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,i=e.originalType,c=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=l(r),f=o,y=u["".concat(c,".").concat(f)]||u[f]||d[f]||i;return r?n.createElement(y,a(a({ref:t},p),{},{components:r})):n.createElement(y,a({ref:t},p))}));function y(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=r.length,a=new Array(i);a[0]=f;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[u]="string"==typeof e?e:o,a[1]=s;for(var l=2;l<i;l++)a[l]=r[l];return n.createElement.apply(null,a)}return n.createElement.apply(null,r)}f.displayName="MDXCreateElement"},6859:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>d,frontMatter:()=>i,metadata:()=>s,toc:()=>l});var n=r(8168),o=(r(6540),r(5680));const i={},a="Conditional",s={unversionedId:"ast-builder/expressions/conditional",id:"ast-builder/expressions/conditional",title:"Conditional",description:"Todo",source:"@site/docs/ast-builder/expressions/conditional.md",sourceDirName:"ast-builder/expressions",slug:"/ast-builder/expressions/conditional",permalink:"/docs/0.16.0/ast-builder/expressions/conditional",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"Deleting Data",permalink:"/docs/0.16.0/ast-builder/statements/data-manipulation/deleting-data"},next:{title:"Nested",permalink:"/docs/0.16.0/ast-builder/expressions/nested"}},c={},l=[{value:"Todo",id:"todo",level:2}],p={toc:l},u="wrapper";function d(e){let{components:t,...r}=e;return(0,o.yg)(u,(0,n.A)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,o.yg)("h1",{id:"conditional"},"Conditional"),(0,o.yg)("h2",{id:"todo"},"Todo"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre"},"- CASE: Returns a value on a condition.\n")))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/a5971d1a.0ab74105.js b/docs/0.16.0/assets/js/a5971d1a.0ab74105.js new file mode 100644 index 00000000..4fd4e9ee --- /dev/null +++ b/docs/0.16.0/assets/js/a5971d1a.0ab74105.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[3892],{5680:(e,t,a)=>{a.d(t,{xA:()=>u,yg:()=>g});var n=a(6540);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function i(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function l(e){for(var t=1;t<arguments.length;t++){var a=null!=arguments[t]?arguments[t]:{};t%2?i(Object(a),!0).forEach((function(t){r(e,t,a[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(a)):i(Object(a)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(a,t))}))}return e}function o(e,t){if(null==e)return{};var a,n,r=function(e,t){if(null==e)return{};var a,n,r={},i=Object.keys(e);for(n=0;n<i.length;n++)a=i[n],t.indexOf(a)>=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)a=i[n],t.indexOf(a)>=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var s=n.createContext({}),d=function(e){var t=n.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):l(l({},t),e)),a},u=function(e){var t=d(e.components);return n.createElement(s.Provider,{value:t},e.children)},p="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,u=o(e,["components","mdxType","originalType","parentName"]),p=d(a),m=r,g=p["".concat(s,".").concat(m)]||p[m]||c[m]||i;return a?n.createElement(g,l(l({ref:t},u),{},{components:a})):n.createElement(g,l({ref:t},u))}));function g(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=a.length,l=new Array(i);l[0]=m;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[p]="string"==typeof e?e:r,l[1]=o;for(var d=2;d<i;d++)l[d]=a[d];return n.createElement.apply(null,l)}return n.createElement.apply(null,a)}m.displayName="MDXCreateElement"},842:(e,t,a)=>{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>c,frontMatter:()=>i,metadata:()=>o,toc:()=>d});var n=a(8168),r=(a(6540),a(5680));const i={sidebar_position:6},l="DATE",o={unversionedId:"sql-syntax/data-types/date",id:"sql-syntax/data-types/date",title:"DATE",description:"In GlueSQL, the DATE data type is used to store date values in the format 'YYYY-MM-DD'. Note that GlueSQL currently does not support timezones.",source:"@site/docs/sql-syntax/data-types/date.md",sourceDirName:"sql-syntax/data-types",slug:"/sql-syntax/data-types/date",permalink:"/docs/0.16.0/sql-syntax/data-types/date",draft:!1,tags:[],version:"current",sidebarPosition:6,frontMatter:{sidebar_position:6},sidebar:"autoSidebar",previous:{title:"DECIMAL",permalink:"/docs/0.16.0/sql-syntax/data-types/decimal"},next:{title:"TIMESTAMP",permalink:"/docs/0.16.0/sql-syntax/data-types/timestamp"}},s={},d=[{value:"Creating a table with DATE columns",id:"creating-a-table-with-date-columns",level:2},{value:"Inserting data into a table with DATE columns",id:"inserting-data-into-a-table-with-date-columns",level:2},{value:"Querying data from a table with DATE columns",id:"querying-data-from-a-table-with-date-columns",level:2},{value:"Filtering data using DATE columns",id:"filtering-data-using-date-columns",level:2},{value:"Performing date arithmetic",id:"performing-date-arithmetic",level:2},{value:"Handling invalid date values",id:"handling-invalid-date-values",level:2},{value:"Conclusion",id:"conclusion",level:2}],u={toc:d},p="wrapper";function c(e){let{components:t,...a}=e;return(0,r.yg)(p,(0,n.A)({},u,a,{components:t,mdxType:"MDXLayout"}),(0,r.yg)("h1",{id:"date"},"DATE"),(0,r.yg)("p",null,"In GlueSQL, the ",(0,r.yg)("inlineCode",{parentName:"p"},"DATE")," data type is used to store date values in the format 'YYYY-MM-DD'. Note that GlueSQL currently does not support timezones."),(0,r.yg)("h2",{id:"creating-a-table-with-date-columns"},"Creating a table with DATE columns"),(0,r.yg)("p",null,"To create a table with columns of type ",(0,r.yg)("inlineCode",{parentName:"p"},"DATE"),", use the ",(0,r.yg)("inlineCode",{parentName:"p"},"CREATE TABLE")," statement:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE DateLog (\n id INTEGER,\n date1 DATE,\n date2 DATE\n);\n")),(0,r.yg)("h2",{id:"inserting-data-into-a-table-with-date-columns"},"Inserting data into a table with DATE columns"),(0,r.yg)("p",null,"To insert data into a table with ",(0,r.yg)("inlineCode",{parentName:"p"},"DATE")," columns, use the ",(0,r.yg)("inlineCode",{parentName:"p"},"INSERT INTO")," statement:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO DateLog VALUES\n (1, '2020-06-11', '2021-03-01'),\n (2, '2020-09-30', '1989-01-01'),\n (3, '2021-05-01', '2021-05-01');\n")),(0,r.yg)("h2",{id:"querying-data-from-a-table-with-date-columns"},"Querying data from a table with DATE columns"),(0,r.yg)("p",null,"To query data from a table with ",(0,r.yg)("inlineCode",{parentName:"p"},"DATE")," columns, use the ",(0,r.yg)("inlineCode",{parentName:"p"},"SELECT")," statement:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT id, date1, date2 FROM DateLog;\n")),(0,r.yg)("h2",{id:"filtering-data-using-date-columns"},"Filtering data using DATE columns"),(0,r.yg)("p",null,"You can use various comparison operators like ",(0,r.yg)("inlineCode",{parentName:"p"},">"),", ",(0,r.yg)("inlineCode",{parentName:"p"},"<"),", ",(0,r.yg)("inlineCode",{parentName:"p"},"<="),", ",(0,r.yg)("inlineCode",{parentName:"p"},">="),", and ",(0,r.yg)("inlineCode",{parentName:"p"},"=")," to filter data based on ",(0,r.yg)("inlineCode",{parentName:"p"},"DATE")," columns:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT * FROM DateLog WHERE date1 > date2;\n\nSELECT * FROM DateLog WHERE date1 <= date2;\n\nSELECT * FROM DateLog WHERE date1 = DATE '2020-06-11';\n\nSELECT * FROM DateLog WHERE date2 < '2000-01-01';\n\nSELECT * FROM DateLog WHERE '1999-01-03' < DATE '2000-01-01';\n")),(0,r.yg)("h2",{id:"performing-date-arithmetic"},"Performing date arithmetic"),(0,r.yg)("p",null,"You can perform arithmetic operations on ",(0,r.yg)("inlineCode",{parentName:"p"},"DATE")," columns using ",(0,r.yg)("inlineCode",{parentName:"p"},"INTERVAL")," and various date arithmetic operators:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT\n id,\n date1 - date2 AS date_sub,\n date1 - INTERVAL '1' DAY AS sub,\n date2 + INTERVAL '1' MONTH AS add\nFROM DateLog;\n")),(0,r.yg)("h2",{id:"handling-invalid-date-values"},"Handling invalid date values"),(0,r.yg)("p",null,"If you try to insert an invalid date value into a ",(0,r.yg)("inlineCode",{parentName:"p"},"DATE")," column, GlueSQL will return an error:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO DateLog VALUES (1, '12345-678', '2021-05-01');\n")),(0,r.yg)("p",null,"This will result in an error similar to the following:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre"},"failed to parse date 12345-678\n")),(0,r.yg)("h2",{id:"conclusion"},"Conclusion"),(0,r.yg)("p",null,"In summary, the ",(0,r.yg)("inlineCode",{parentName:"p"},"DATE")," data type in GlueSQL allows you to store and manipulate date values in your database. You can create tables with ",(0,r.yg)("inlineCode",{parentName:"p"},"DATE")," columns, insert and query data, filter data based on date comparisons, and perform date arithmetic using various operators and intervals. Always remember to use valid date formats when inserting data into ",(0,r.yg)("inlineCode",{parentName:"p"},"DATE")," columns to avoid errors."))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/a6aa9e1f.c5d6d672.js b/docs/0.16.0/assets/js/a6aa9e1f.c5d6d672.js new file mode 100644 index 00000000..e68d1fa2 --- /dev/null +++ b/docs/0.16.0/assets/js/a6aa9e1f.c5d6d672.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[7643],{7785:(e,t,a)=>{a.r(t),a.d(t,{default:()=>u});var n=a(6540),l=a(53),r=a(4586),i=a(1003),o=a(7559),s=a(6669),c=a(7713),m=a(1463),g=a(3892);function p(e){const{metadata:t}=e,{siteConfig:{title:a}}=(0,r.A)(),{blogDescription:l,blogTitle:o,permalink:s}=t,c="/"===s?a:o;return n.createElement(n.Fragment,null,n.createElement(i.be,{title:c,description:l}),n.createElement(m.A,{tag:"blog_posts_list"}))}function d(e){const{metadata:t,items:a,sidebar:l}=e;return n.createElement(s.A,{sidebar:l},n.createElement(g.A,{items:a}),n.createElement(c.A,{metadata:t}))}function u(e){return n.createElement(i.e3,{className:(0,l.A)(o.G.wrapper.blogPages,o.G.page.blogListPage)},n.createElement(p,e),n.createElement(d,e))}},7713:(e,t,a)=>{a.d(t,{A:()=>i});var n=a(6540),l=a(1312),r=a(9022);function i(e){const{metadata:t}=e,{previousPage:a,nextPage:i}=t;return n.createElement("nav",{className:"pagination-nav","aria-label":(0,l.T)({id:"theme.blog.paginator.navAriaLabel",message:"Blog list page navigation",description:"The ARIA label for the blog pagination"})},a&&n.createElement(r.A,{permalink:a,title:n.createElement(l.A,{id:"theme.blog.paginator.newerEntries",description:"The label used to navigate to the newer blog posts page (previous page)"},"Newer Entries")}),i&&n.createElement(r.A,{permalink:i,title:n.createElement(l.A,{id:"theme.blog.paginator.olderEntries",description:"The label used to navigate to the older blog posts page (next page)"},"Older Entries"),isNext:!0}))}},3892:(e,t,a)=>{a.d(t,{A:()=>i});var n=a(6540),l=a(7131),r=a(8258);function i(e){let{items:t,component:a=r.A}=e;return n.createElement(n.Fragment,null,t.map((e=>{let{content:t}=e;return n.createElement(l.i,{key:t.metadata.permalink,content:t},n.createElement(a,null,n.createElement(t,null)))})))}}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/a6b6486c.7066e9bb.js b/docs/0.16.0/assets/js/a6b6486c.7066e9bb.js new file mode 100644 index 00000000..d9a61fe2 --- /dev/null +++ b/docs/0.16.0/assets/js/a6b6486c.7066e9bb.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[3823],{5680:(e,t,r)=>{r.d(t,{xA:()=>s,yg:()=>y});var n=r(6540);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function a(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?i(Object(r),!0).forEach((function(t){o(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):i(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function c(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=n.createContext({}),u=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},s=function(e){var t=u(e.components);return n.createElement(l.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},f=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,i=e.originalType,l=e.parentName,s=c(e,["components","mdxType","originalType","parentName"]),p=u(r),f=o,y=p["".concat(l,".").concat(f)]||p[f]||d[f]||i;return r?n.createElement(y,a(a({ref:t},s),{},{components:r})):n.createElement(y,a({ref:t},s))}));function y(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=r.length,a=new Array(i);a[0]=f;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c[p]="string"==typeof e?e:o,a[1]=c;for(var u=2;u<i;u++)a[u]=r[u];return n.createElement.apply(null,a)}return n.createElement.apply(null,r)}f.displayName="MDXCreateElement"},4492:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>a,default:()=>d,frontMatter:()=>i,metadata:()=>c,toc:()=>u});var n=r(8168),o=(r(6540),r(5680));const i={},a="Point Creation",c={unversionedId:"ast-builder/functions/geometry/point-creation",id:"ast-builder/functions/geometry/point-creation",title:"Point Creation",description:"Todo",source:"@site/docs/ast-builder/functions/geometry/point-creation.md",sourceDirName:"ast-builder/functions/geometry",slug:"/ast-builder/functions/geometry/point-creation",permalink:"/docs/0.16.0/ast-builder/functions/geometry/point-creation",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"Distance Calculation",permalink:"/docs/0.16.0/ast-builder/functions/geometry/distance-calculation"},next:{title:"Null Handling",permalink:"/docs/0.16.0/ast-builder/functions/others/null-handling"}},l={},u=[{value:"Todo",id:"todo",level:2}],s={toc:u},p="wrapper";function d(e){let{components:t,...r}=e;return(0,o.yg)(p,(0,n.A)({},s,r,{components:t,mdxType:"MDXLayout"}),(0,o.yg)("h1",{id:"point-creation"},"Point Creation"),(0,o.yg)("h2",{id:"todo"},"Todo"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre"},"- POINT: Creates a geometric point with an x and y coordinate.\n")))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/a7153b78.a2b5a6f6.js b/docs/0.16.0/assets/js/a7153b78.a2b5a6f6.js new file mode 100644 index 00000000..8b7db4cd --- /dev/null +++ b/docs/0.16.0/assets/js/a7153b78.a2b5a6f6.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[3071],{5680:(e,t,n)=>{n.d(t,{xA:()=>u,yg:()=>d});var r=n(6540);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},i=Object.keys(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=r.createContext({}),c=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},u=function(e){var t=c(e.components);return r.createElement(l.Provider,{value:t},e.children)},g="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),g=c(n),m=a,d=g["".concat(l,".").concat(m)]||g[m]||p[m]||i;return n?r.createElement(d,o(o({ref:t},u),{},{components:n})):r.createElement(d,o({ref:t},u))}));function d(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,o=new Array(i);o[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[g]="string"==typeof e?e:a,o[1]=s;for(var c=2;c<i;c++)o[c]=n[c];return r.createElement.apply(null,o)}return r.createElement.apply(null,n)}m.displayName="MDXCreateElement"},6162:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>o,default:()=>p,frontMatter:()=>i,metadata:()=>s,toc:()=>c});var r=n(8168),a=(n(6540),n(5680));const i={},o="TO_TIME",s={unversionedId:"sql-syntax/functions/datetime/to-time",id:"sql-syntax/functions/datetime/to-time",title:"TO_TIME",description:"The TO_TIME function in SQL is used to convert a string into a TIME. This function takes two arguments, the string to be converted and a format string that specifies the format of the input string.",source:"@site/docs/sql-syntax/functions/datetime/to-time.md",sourceDirName:"sql-syntax/functions/datetime",slug:"/sql-syntax/functions/datetime/to-time",permalink:"/docs/0.16.0/sql-syntax/functions/datetime/to-time",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"TO_DATE",permalink:"/docs/0.16.0/sql-syntax/functions/datetime/to-date"},next:{title:"TO_TIMESTAMP",permalink:"/docs/0.16.0/sql-syntax/functions/datetime/to-timestamp"}},l={},c=[{value:"Syntax",id:"syntax",level:2},{value:"Examples",id:"examples",level:2},{value:"Converting a string to a TIME",id:"converting-a-string-to-a-time",level:3},{value:"Selecting a converted string to a TIME",id:"selecting-a-converted-string-to-a-time",level:3},{value:"Error Handling",id:"error-handling",level:2}],u={toc:c},g="wrapper";function p(e){let{components:t,...n}=e;return(0,a.yg)(g,(0,r.A)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"to_time"},"TO_TIME"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"TO_TIME")," function in SQL is used to convert a string into a TIME. This function takes two arguments, the string to be converted and a format string that specifies the format of the input string."),(0,a.yg)("h2",{id:"syntax"},"Syntax"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"TO_TIME(string, format)\n")),(0,a.yg)("h2",{id:"examples"},"Examples"),(0,a.yg)("h3",{id:"converting-a-string-to-a-time"},"Converting a string to a TIME"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"VALUES(TO_TIME('23:56:04', '%H:%M:%S'));\n")),(0,a.yg)("p",null,"In this example, the string '23:56:04' is converted into a TIME using the format '%H:%M:%S', where %H is the two-digit hour, %M is the two-digit minute, and %S is the two-digit second."),(0,a.yg)("h3",{id:"selecting-a-converted-string-to-a-time"},"Selecting a converted string to a TIME"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT TO_TIME('23:56:04','%H:%M:%S') AS time;\n")),(0,a.yg)("p",null,"In this example, the string '23:56:04' is converted into a TIME using the format '%H:%M:%S' and selected as 'time'."),(0,a.yg)("h2",{id:"error-handling"},"Error Handling"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"TO_TIME")," function requires a string value as its first argument. If a non-string value is provided, it will return an error."),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT TO_TIME(TIME '23:56:04','%H:%M:%S') AS time;\n")),(0,a.yg)("p",null,"In this case, the TIME '23:56:04' is not a string and will cause an error."),(0,a.yg)("p",null,"Additionally, if the format string does not match the format of the input string, an error will also be returned. For example:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT TO_TIME('23:56', '%H:%M:%S') AS time;\n")),(0,a.yg)("p",null,"In this case, the format string '%H:%M:%S' does not match the input string '23:56', so an error will be returned."))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/a7e6874c.32075221.js b/docs/0.16.0/assets/js/a7e6874c.32075221.js new file mode 100644 index 00000000..481e76aa --- /dev/null +++ b/docs/0.16.0/assets/js/a7e6874c.32075221.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[8738],{5680:(e,t,n)=>{n.d(t,{xA:()=>u,yg:()=>m});var r=n(6540);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function l(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},o=Object.keys(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var i=r.createContext({}),p=function(e){var t=r.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},u=function(e){var t=p(e.components);return r.createElement(i.Provider,{value:t},e.children)},c="mdxType",y={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},g=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,i=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),c=p(n),g=a,m=c["".concat(i,".").concat(g)]||c[g]||y[g]||o;return n?r.createElement(m,l(l({ref:t},u),{},{components:n})):r.createElement(m,l({ref:t},u))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,l=new Array(o);l[0]=g;var s={};for(var i in t)hasOwnProperty.call(t,i)&&(s[i]=t[i]);s.originalType=e,s[c]="string"==typeof e?e:a,l[1]=s;for(var p=2;p<o;p++)l[p]=n[p];return r.createElement.apply(null,l)}return r.createElement.apply(null,n)}g.displayName="MDXCreateElement"},5653:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>i,contentTitle:()=>l,default:()=>y,frontMatter:()=>o,metadata:()=>s,toc:()=>p});var r=n(8168),a=(n(6540),n(5680));const o={},l="POWER",s={unversionedId:"sql-syntax/functions/math/power",id:"sql-syntax/functions/math/power",title:"POWER",description:"The POWER function is used to raise a number to the power of another number. It takes two arguments, the base and the exponent, both of which must be of the FLOAT type. The result will also be of the FLOAT type.",source:"@site/docs/sql-syntax/functions/math/power.md",sourceDirName:"sql-syntax/functions/math",slug:"/sql-syntax/functions/math/power",permalink:"/docs/0.16.0/sql-syntax/functions/math/power",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"PI",permalink:"/docs/0.16.0/sql-syntax/functions/math/pi"},next:{title:"RADIANS",permalink:"/docs/0.16.0/sql-syntax/functions/math/radians"}},i={},p=[{value:"Syntax",id:"syntax",level:2},{value:"Examples",id:"examples",level:2},{value:"Error Cases",id:"error-cases",level:2}],u={toc:p},c="wrapper";function y(e){let{components:t,...n}=e;return(0,a.yg)(c,(0,r.A)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"power"},"POWER"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"POWER")," function is used to raise a number to the power of another number. It takes two arguments, the base and the exponent, both of which must be of the FLOAT type. The result will also be of the FLOAT type."),(0,a.yg)("h2",{id:"syntax"},"Syntax"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"POWER(base, exponent)\n")),(0,a.yg)("h2",{id:"examples"},"Examples"),(0,a.yg)("ol",null,(0,a.yg)("li",{parentName:"ol"},"Using the ",(0,a.yg)("inlineCode",{parentName:"li"},"POWER")," function:")),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT POWER(2.0, 4) as power_1;\n-- Result: 16.0\n")),(0,a.yg)("ol",{start:2},(0,a.yg)("li",{parentName:"ol"},"Using the ",(0,a.yg)("inlineCode",{parentName:"li"},"POWER")," function with a decimal:")),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT POWER(0.07, 3) as power_2;\n-- Result: 0.000343\n")),(0,a.yg)("ol",{start:3},(0,a.yg)("li",{parentName:"ol"},"Using the ",(0,a.yg)("inlineCode",{parentName:"li"},"POWER")," function with zero:")),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT POWER(0, 4) as power_with_zero;\n-- Result: 0.0\n\nSELECT POWER(3, 0) as power_to_zero;\n-- Result: 1.0\n")),(0,a.yg)("h2",{id:"error-cases"},"Error Cases"),(0,a.yg)("ol",null,(0,a.yg)("li",{parentName:"ol"},"The ",(0,a.yg)("inlineCode",{parentName:"li"},"POWER")," function requires both arguments to be of FLOAT type:")),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT POWER('string', 'string') AS power;\n-- Error: FunctionRequiresFloatValue(\"POWER\")\n")),(0,a.yg)("ol",{start:2},(0,a.yg)("li",{parentName:"ol"},"The ",(0,a.yg)("inlineCode",{parentName:"li"},"POWER")," function requires the base to be of FLOAT type:")),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT POWER('string', 2.0) AS power;\n-- Error: FunctionRequiresFloatValue(\"POWER\")\n")),(0,a.yg)("ol",{start:3},(0,a.yg)("li",{parentName:"ol"},"The ",(0,a.yg)("inlineCode",{parentName:"li"},"POWER")," function requires the exponent to be of FLOAT type:")),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT POWER(2.0, 'string') AS power;\n-- Error: FunctionRequiresFloatValue(\"POWER\")\n")))}y.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/a87d47f1.638107c7.js b/docs/0.16.0/assets/js/a87d47f1.638107c7.js new file mode 100644 index 00000000..dd554ac1 --- /dev/null +++ b/docs/0.16.0/assets/js/a87d47f1.638107c7.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[133],{4068:s=>{s.exports=JSON.parse('{"permalink":"/docs/0.16.0/blog/tags/v-0-14","page":1,"postsPerPage":10,"totalPages":1,"totalCount":1,"blogDescription":"Blog","blogTitle":"Blog"}')}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/a8d11699.0e5d0034.js b/docs/0.16.0/assets/js/a8d11699.0e5d0034.js new file mode 100644 index 00000000..c3f8c591 --- /dev/null +++ b/docs/0.16.0/assets/js/a8d11699.0e5d0034.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[5834],{5680:(e,t,n)=>{n.d(t,{xA:()=>p,yg:()=>g});var a=n(6540);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function l(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?r(Object(n),!0).forEach((function(t){i(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):r(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function o(e,t){if(null==e)return{};var n,a,i=function(e,t){if(null==e)return{};var n,a,i={},r=Object.keys(e);for(a=0;a<r.length;a++)n=r[a],t.indexOf(n)>=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a<r.length;a++)n=r[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=a.createContext({}),m=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},p=function(e){var t=m(e.components);return a.createElement(s.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},c=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,r=e.originalType,s=e.parentName,p=o(e,["components","mdxType","originalType","parentName"]),u=m(n),c=i,g=u["".concat(s,".").concat(c)]||u[c]||d[c]||r;return n?a.createElement(g,l(l({ref:t},p),{},{components:n})):a.createElement(g,l({ref:t},p))}));function g(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=n.length,l=new Array(r);l[0]=c;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[u]="string"==typeof e?e:i,l[1]=o;for(var m=2;m<r;m++)l[m]=n[m];return a.createElement.apply(null,l)}return a.createElement.apply(null,n)}c.displayName="MDXCreateElement"},7136:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>d,frontMatter:()=>r,metadata:()=>o,toc:()=>m});var a=n(8168),i=(n(6540),n(5680));const r={sidebar_position:7},l="TIMESTAMP",o={unversionedId:"sql-syntax/data-types/timestamp",id:"sql-syntax/data-types/timestamp",title:"TIMESTAMP",description:"In GlueSQL, the TIMESTAMP data type is used to store date and time values in the format 'YYYY-MM-DD HHSS.SSSS'. Although timezone information can be included in the input string, GlueSQL stores all TIMESTAMP values in UTC, discarding the timezone information.",source:"@site/docs/sql-syntax/data-types/timestamp.md",sourceDirName:"sql-syntax/data-types",slug:"/sql-syntax/data-types/timestamp",permalink:"/docs/0.16.0/sql-syntax/data-types/timestamp",draft:!1,tags:[],version:"current",sidebarPosition:7,frontMatter:{sidebar_position:7},sidebar:"autoSidebar",previous:{title:"DATE",permalink:"/docs/0.16.0/sql-syntax/data-types/date"},next:{title:"TIME",permalink:"/docs/0.16.0/sql-syntax/data-types/time"}},s={},m=[{value:"Creating a table with TIMESTAMP columns",id:"creating-a-table-with-timestamp-columns",level:2},{value:"Inserting data into a table with TIMESTAMP columns",id:"inserting-data-into-a-table-with-timestamp-columns",level:2},{value:"Querying data from a table with TIMESTAMP columns",id:"querying-data-from-a-table-with-timestamp-columns",level:2},{value:"Filtering data using TIMESTAMP columns",id:"filtering-data-using-timestamp-columns",level:2},{value:"Performing timestamp arithmetic",id:"performing-timestamp-arithmetic",level:2},{value:"Handling invalid timestamp values",id:"handling-invalid-timestamp-values",level:2},{value:"Conclusion",id:"conclusion",level:2}],p={toc:m},u="wrapper";function d(e){let{components:t,...n}=e;return(0,i.yg)(u,(0,a.A)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,i.yg)("h1",{id:"timestamp"},"TIMESTAMP"),(0,i.yg)("p",null,"In GlueSQL, the ",(0,i.yg)("inlineCode",{parentName:"p"},"TIMESTAMP")," data type is used to store date and time values in the format 'YYYY-MM-DD HH:MM:SS.SSSS'. Although timezone information can be included in the input string, GlueSQL stores all ",(0,i.yg)("inlineCode",{parentName:"p"},"TIMESTAMP")," values in UTC, discarding the timezone information."),(0,i.yg)("h2",{id:"creating-a-table-with-timestamp-columns"},"Creating a table with TIMESTAMP columns"),(0,i.yg)("p",null,"To create a table with columns of type ",(0,i.yg)("inlineCode",{parentName:"p"},"TIMESTAMP"),", use the ",(0,i.yg)("inlineCode",{parentName:"p"},"CREATE TABLE")," statement:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE TimestampLog (\n id INTEGER,\n t1 TIMESTAMP,\n t2 TIMESTAMP\n);\n")),(0,i.yg)("h2",{id:"inserting-data-into-a-table-with-timestamp-columns"},"Inserting data into a table with TIMESTAMP columns"),(0,i.yg)("p",null,"To insert data into a table with ",(0,i.yg)("inlineCode",{parentName:"p"},"TIMESTAMP")," columns, use the ",(0,i.yg)("inlineCode",{parentName:"p"},"INSERT INTO")," statement:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO TimestampLog VALUES\n (1, '2020-06-11 11:23:11Z', '2021-03-01'),\n (2, '2020-09-30 12:00:00 -07:00', '1989-01-01T00:01:00+09:00'),\n (3, '2021-04-30T07:00:00.1234-17:00', '2021-05-01T09:00:00.1234+09:00');\n")),(0,i.yg)("p",null,"The input strings include timezone information, but GlueSQL will convert and store them as UTC timestamps."),(0,i.yg)("h2",{id:"querying-data-from-a-table-with-timestamp-columns"},"Querying data from a table with TIMESTAMP columns"),(0,i.yg)("p",null,"To query data from a table with ",(0,i.yg)("inlineCode",{parentName:"p"},"TIMESTAMP")," columns, use the ",(0,i.yg)("inlineCode",{parentName:"p"},"SELECT")," statement:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT id, t1, t2 FROM TimestampLog;\n")),(0,i.yg)("h2",{id:"filtering-data-using-timestamp-columns"},"Filtering data using TIMESTAMP columns"),(0,i.yg)("p",null,"You can use various comparison operators like ",(0,i.yg)("inlineCode",{parentName:"p"},">"),", ",(0,i.yg)("inlineCode",{parentName:"p"},"<"),", ",(0,i.yg)("inlineCode",{parentName:"p"},"<="),", ",(0,i.yg)("inlineCode",{parentName:"p"},">="),", and ",(0,i.yg)("inlineCode",{parentName:"p"},"=")," to filter data based on ",(0,i.yg)("inlineCode",{parentName:"p"},"TIMESTAMP")," columns:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT * FROM TimestampLog WHERE t1 > t2;\n\nSELECT * FROM TimestampLog WHERE t1 = t2;\n\nSELECT * FROM TimestampLog WHERE t1 = '2020-06-11T14:23:11+0300';\n\nSELECT * FROM TimestampLog WHERE t2 < TIMESTAMP '2000-01-01';\n")),(0,i.yg)("h2",{id:"performing-timestamp-arithmetic"},"Performing timestamp arithmetic"),(0,i.yg)("p",null,"You can perform arithmetic operations on ",(0,i.yg)("inlineCode",{parentName:"p"},"TIMESTAMP")," columns using ",(0,i.yg)("inlineCode",{parentName:"p"},"INTERVAL"),":"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT id, t1 - t2 AS timestamp_sub FROM TimestampLog;\n\nSELECT\n id,\n t1 - INTERVAL '1' DAY AS sub,\n t2 + INTERVAL '1' MONTH AS add\nFROM TimestampLog;\n")),(0,i.yg)("h2",{id:"handling-invalid-timestamp-values"},"Handling invalid timestamp values"),(0,i.yg)("p",null,"If you try to insert an invalid timestamp value into a ",(0,i.yg)("inlineCode",{parentName:"p"},"TIMESTAMP")," column, GlueSQL will return an error:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO TimestampLog VALUES (1, '12345-678', '2021-05-01');\n")),(0,i.yg)("p",null,"This will result in an error similar to the following:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre"},"failed to parse timestamp: 12345-678\n")),(0,i.yg)("h2",{id:"conclusion"},"Conclusion"),(0,i.yg)("p",null,"In GlueSQL, the TIMESTAMP data type allows you to store date and time values with precision up to milliseconds. The provided code snippet demonstrates how to create a table with TIMESTAMP columns, insert data into it, and perform various queries and operations on the data. When inserting a TIMESTAMP value, the timezone information is removed, and the data is stored in UTC. This ensures that all time values are consistent and can be easily converted to different time zones when needed."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/a9e26133.7429af4a.js b/docs/0.16.0/assets/js/a9e26133.7429af4a.js new file mode 100644 index 00000000..51402e28 --- /dev/null +++ b/docs/0.16.0/assets/js/a9e26133.7429af4a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[4073],{5680:(e,t,n)=>{n.d(t,{xA:()=>c,yg:()=>g});var r=n(6540);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?l(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):l(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function o(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},l=Object.keys(e);for(r=0;r<l.length;r++)n=l[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(r=0;r<l.length;r++)n=l[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),u=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},c=function(e){var t=u(e.components);return r.createElement(s.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},y=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,l=e.originalType,s=e.parentName,c=o(e,["components","mdxType","originalType","parentName"]),p=u(n),y=a,g=p["".concat(s,".").concat(y)]||p[y]||d[y]||l;return n?r.createElement(g,i(i({ref:t},c),{},{components:n})):r.createElement(g,i({ref:t},c))}));function g(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var l=n.length,i=new Array(l);i[0]=y;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[p]="string"==typeof e?e:a,i[1]=o;for(var u=2;u<l;u++)i[u]=n[u];return r.createElement.apply(null,i)}return r.createElement.apply(null,n)}y.displayName="MDXCreateElement"},8760:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>d,frontMatter:()=>l,metadata:()=>o,toc:()=>u});var r=n(8168),a=(n(6540),n(5680));const l={},i="INET",o={unversionedId:"sql-syntax/data-types/inet",id:"sql-syntax/data-types/inet",title:"INET",description:"The INET data type in SQL is used to store IPv4 and IPv6 addresses. These addresses can be compared, filtered, and sorted using standard SQL operations.",source:"@site/docs/sql-syntax/data-types/inet.md",sourceDirName:"sql-syntax/data-types",slug:"/sql-syntax/data-types/inet",permalink:"/docs/0.16.0/sql-syntax/data-types/inet",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"BYTEA",permalink:"/docs/0.16.0/sql-syntax/data-types/bytea"},next:{title:"UUID",permalink:"/docs/0.16.0/sql-syntax/data-types/uuid"}},s={},u=[{value:"Creating a table with an INET column",id:"creating-a-table-with-an-inet-column",level:2},{value:"Inserting data into the INET column",id:"inserting-data-into-the-inet-column",level:2},{value:"Querying data from the INET column",id:"querying-data-from-the-inet-column",level:2},{value:"Filtering data using the INET column",id:"filtering-data-using-the-inet-column",level:2},{value:"Querying for specific IP addresses",id:"querying-for-specific-ip-addresses",level:2}],c={toc:u},p="wrapper";function d(e){let{components:t,...n}=e;return(0,a.yg)(p,(0,r.A)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"inet"},"INET"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"INET")," data type in SQL is used to store IPv4 and IPv6 addresses. These addresses can be compared, filtered, and sorted using standard SQL operations."),(0,a.yg)("p",null,"Here's an example of how to create a table, insert data, and query data using the ",(0,a.yg)("inlineCode",{parentName:"p"},"INET")," data type:"),(0,a.yg)("h2",{id:"creating-a-table-with-an-inet-column"},"Creating a table with an INET column"),(0,a.yg)("p",null,"To create a table with an INET column, use the following SQL syntax:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE computer (ip INET);\n")),(0,a.yg)("h2",{id:"inserting-data-into-the-inet-column"},"Inserting data into the INET column"),(0,a.yg)("p",null,"To insert data into the INET column, provide the IP addresses as strings or integers:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO computer VALUES\n ('::1'),\n ('127.0.0.1'),\n ('0.0.0.0'),\n (4294967295),\n (9876543210);\n")),(0,a.yg)("h2",{id:"querying-data-from-the-inet-column"},"Querying data from the INET column"),(0,a.yg)("p",null,"To query data from the INET column, use standard SQL syntax:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT * FROM computer;\n")),(0,a.yg)("p",null,"This query will return the following result:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre"},"ip\n-----------------\n::1\n127.0.0.1\n0.0.0.0\n255.255.255.255\n::2:4cb0:16ea\n")),(0,a.yg)("h2",{id:"filtering-data-using-the-inet-column"},"Filtering data using the INET column"),(0,a.yg)("p",null,"You can filter data using the INET column with standard SQL operators:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT * FROM computer WHERE ip > '127.0.0.1';\n")),(0,a.yg)("p",null,"This query will return the following result:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre"},"ip\n-----------------\n::1\n255.255.255.255\n::2:4cb0:16ea\n")),(0,a.yg)("h2",{id:"querying-for-specific-ip-addresses"},"Querying for specific IP addresses"),(0,a.yg)("p",null,"To query for specific IP addresses, use the following syntax:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT * FROM computer WHERE ip = '127.0.0.1';\n")),(0,a.yg)("p",null,"This query will return the following result:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre"},"ip\n---------\n127.0.0.1\n")))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/aa1cf9a2.52828c0e.js b/docs/0.16.0/assets/js/aa1cf9a2.52828c0e.js new file mode 100644 index 00000000..4f6c68f1 --- /dev/null +++ b/docs/0.16.0/assets/js/aa1cf9a2.52828c0e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[5363],{5680:(e,t,n)=>{n.d(t,{xA:()=>y,yg:()=>c});var r=n(6540);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},i=Object.keys(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var p=r.createContext({}),s=function(e){var t=r.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},y=function(e){var t=s(e.components);return r.createElement(p.Provider,{value:t},e.children)},u="mdxType",g={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,p=e.parentName,y=l(e,["components","mdxType","originalType","parentName"]),u=s(n),d=a,c=u["".concat(p,".").concat(d)]||u[d]||g[d]||i;return n?r.createElement(c,o(o({ref:t},y),{},{components:n})):r.createElement(c,o({ref:t},y))}));function c(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,o=new Array(i);o[0]=d;var l={};for(var p in t)hasOwnProperty.call(t,p)&&(l[p]=t[p]);l.originalType=e,l[u]="string"==typeof e?e:a,o[1]=l;for(var s=2;s<i;s++)o[s]=n[s];return r.createElement.apply(null,o)}return r.createElement.apply(null,n)}d.displayName="MDXCreateElement"},93:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>o,default:()=>g,frontMatter:()=>i,metadata:()=>l,toc:()=>s});var r=n(8168),a=(n(6540),n(5680));const i={sidebar_position:2},o="Integer Types",l={unversionedId:"sql-syntax/data-types/integers",id:"sql-syntax/data-types/integers",title:"Integer Types",description:"GlueSQL supports the following integer data types:",source:"@site/docs/sql-syntax/data-types/integers.md",sourceDirName:"sql-syntax/data-types",slug:"/sql-syntax/data-types/integers",permalink:"/docs/0.16.0/sql-syntax/data-types/integers",draft:!1,tags:[],version:"current",sidebarPosition:2,frontMatter:{sidebar_position:2},sidebar:"autoSidebar",previous:{title:"BOOLEAN",permalink:"/docs/0.16.0/sql-syntax/data-types/boolean"},next:{title:"FLOAT",permalink:"/docs/0.16.0/sql-syntax/data-types/float"}},p={},s=[],y={toc:s},u="wrapper";function g(e){let{components:t,...n}=e;return(0,a.yg)(u,(0,r.A)({},y,n,{components:t,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"integer-types"},"Integer Types"),(0,a.yg)("p",null,"GlueSQL supports the following integer data types:"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"INT8"),": 8-bit signed integer"),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"INT16"),": 16-bit signed integer"),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"INT32"),": 32-bit signed integer"),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"INT")," or ",(0,a.yg)("inlineCode",{parentName:"li"},"INTEGER"),": 64-bit signed integer (default)"),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"INT128"),": 128-bit signed integer"),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"UINT8"),": 8-bit unsigned integer"),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"UINT16"),": 16-bit unsigned integer"),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"UINT32"),": 32-bit unsigned integer"),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"UINT64"),": 64-bit unsigned integer"),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"UINT128"),": 128-bit unsigned integer")),(0,a.yg)("p",null,"For general purposes, you can use ",(0,a.yg)("inlineCode",{parentName:"p"},"INTEGER")," to specify a 64-bit signed integer."),(0,a.yg)("p",null,"Here's an example of how to create a table with integer data types:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre"},"CREATE TABLE Item (\n field_one INTEGER,\n field_two INTEGER\n);\n")),(0,a.yg)("p",null,"You can insert data into the ",(0,a.yg)("inlineCode",{parentName:"p"},"Item")," table as follows:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre"},"INSERT INTO Item VALUES (1, -1), (-2, 2), (3, 3), (-4, -4);\n")),(0,a.yg)("p",null,"You can perform arithmetic operations such as addition, subtraction, multiplication, division, and modulo on integer columns. Note that if you perform arithmetic operations on columns with different integer types, GlueSQL will automatically convert the types of the operands to match the type of the left-hand operand. For example, if you perform ",(0,a.yg)("inlineCode",{parentName:"p"},"UINT8 + INT64"),", GlueSQL will convert the ",(0,a.yg)("inlineCode",{parentName:"p"},"INT64")," operand to ",(0,a.yg)("inlineCode",{parentName:"p"},"UINT8")," and then perform the addition."),(0,a.yg)("p",null,"Integer types are an important part of SQL, and you can use them to store data ranging from small whole numbers to large integers. By understanding how to use integer types in your database, you can write efficient and effective SQL queries that work with a wide range of data."))}g.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/acfabe81.2547b40d.js b/docs/0.16.0/assets/js/acfabe81.2547b40d.js new file mode 100644 index 00000000..b9f6fe29 --- /dev/null +++ b/docs/0.16.0/assets/js/acfabe81.2547b40d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[2450],{5680:(e,t,n)=>{n.d(t,{xA:()=>m,yg:()=>y});var o=n(6540);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function r(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?a(Object(n),!0).forEach((function(t){i(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):a(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,o,i=function(e,t){if(null==e)return{};var n,o,i={},a=Object.keys(e);for(o=0;o<a.length;o++)n=a[o],t.indexOf(n)>=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o<a.length;o++)n=a[o],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var l=o.createContext({}),c=function(e){var t=o.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},m=function(e){var t=c(e.components);return o.createElement(l.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},u=o.forwardRef((function(e,t){var n=e.components,i=e.mdxType,a=e.originalType,l=e.parentName,m=s(e,["components","mdxType","originalType","parentName"]),p=c(n),u=i,y=p["".concat(l,".").concat(u)]||p[u]||d[u]||a;return n?o.createElement(y,r(r({ref:t},m),{},{components:n})):o.createElement(y,r({ref:t},m))}));function y(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var a=n.length,r=new Array(a);r[0]=u;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[p]="string"==typeof e?e:i,r[1]=s;for(var c=2;c<a;c++)r[c]=n[c];return o.createElement.apply(null,r)}return o.createElement.apply(null,n)}u.displayName="MDXCreateElement"},5490:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>r,default:()=>d,frontMatter:()=>a,metadata:()=>s,toc:()=>c});var o=n(8168),i=(n(6540),n(5680));const a={},r="Conversion",s={unversionedId:"ast-builder/functions/date-&-time/conversion",id:"ast-builder/functions/date-&-time/conversion",title:"Conversion",description:"GlueSQL provides date and time conversion functions that allow you to convert text data to datetime data types such as Date, Time, and Timestamp. These functions are todate, totime, and to_timestamp.",source:"@site/docs/ast-builder/functions/date-&-time/conversion.md",sourceDirName:"ast-builder/functions/date-&-time",slug:"/ast-builder/functions/date-&-time/conversion",permalink:"/docs/0.16.0/ast-builder/functions/date-&-time/conversion",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"Trigonometric",permalink:"/docs/0.16.0/ast-builder/functions/math/trigonometric"},next:{title:"Current Date and Time",permalink:"/docs/0.16.0/ast-builder/functions/date-&-time/current-date-and-time"}},l={},c=[{value:"Date Conversion - to_date",id:"date-conversion---to_date",level:2},{value:"Time Conversion - to_time",id:"time-conversion---to_time",level:2},{value:"Timestamp Conversion - to_timestamp",id:"timestamp-conversion---to_timestamp",level:2}],m={toc:c},p="wrapper";function d(e){let{components:t,...n}=e;return(0,i.yg)(p,(0,o.A)({},m,n,{components:t,mdxType:"MDXLayout"}),(0,i.yg)("h1",{id:"conversion"},"Conversion"),(0,i.yg)("p",null,"GlueSQL provides date and time conversion functions that allow you to convert text data to datetime data types such as Date, Time, and Timestamp. These functions are ",(0,i.yg)("inlineCode",{parentName:"p"},"to_date"),", ",(0,i.yg)("inlineCode",{parentName:"p"},"to_time"),", and ",(0,i.yg)("inlineCode",{parentName:"p"},"to_timestamp"),"."),(0,i.yg)("p",null,"For this tutorial, we assume there's a table named ",(0,i.yg)("inlineCode",{parentName:"p"},"Visitor")," with various columns including ",(0,i.yg)("inlineCode",{parentName:"p"},"visit_date"),", ",(0,i.yg)("inlineCode",{parentName:"p"},"visit_time"),", and ",(0,i.yg)("inlineCode",{parentName:"p"},"visit_time_stamp")," which are of ",(0,i.yg)("inlineCode",{parentName:"p"},"TEXT")," type."),(0,i.yg)("h2",{id:"date-conversion---to_date"},"Date Conversion - to_date"),(0,i.yg)("p",null,"The ",(0,i.yg)("inlineCode",{parentName:"p"},"to_date")," function converts a text string to a date."),(0,i.yg)("p",null,"There are two ways to call the ",(0,i.yg)("inlineCode",{parentName:"p"},"to_date")," function in GlueSQL:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Visitor")\n .select()\n .project("id")\n .project("name")\n .project(col("visit_date").to_date("\'%Y-%m-%d\'")) // Method 1: Calling the to_date method on a column\n .project(to_date("visit_date", "\'%Y-%m-%d\'")) // Method 2: Using the to_date function directly\n .execute(glue)\n .await;\n')),(0,i.yg)("h2",{id:"time-conversion---to_time"},"Time Conversion - to_time"),(0,i.yg)("p",null,"The ",(0,i.yg)("inlineCode",{parentName:"p"},"to_time")," function converts a text string to a time."),(0,i.yg)("p",null,"There are two ways to call the ",(0,i.yg)("inlineCode",{parentName:"p"},"to_time")," function in GlueSQL:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Visitor")\n .select()\n .project("id")\n .project("name")\n .project(col("visit_time").to_time("\'%H:%M:%S\'")) // Method 1: Calling the to_time method on a column\n .project(to_time("visit_time", "\'%H:%M:%S\'")) // Method 2: Using the to_time function directly\n .execute(glue)\n .await;\n')),(0,i.yg)("h2",{id:"timestamp-conversion---to_timestamp"},"Timestamp Conversion - to_timestamp"),(0,i.yg)("p",null,"The ",(0,i.yg)("inlineCode",{parentName:"p"},"to_timestamp")," function converts a text string to a timestamp."),(0,i.yg)("p",null,"There are two ways to call the ",(0,i.yg)("inlineCode",{parentName:"p"},"to_timestamp")," function in GlueSQL:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Visitor")\n .select()\n .project("id")\n .project("name")\n .project(col("visit_time_stamp").to_timestamp("\'%Y-%m-%d %H:%M:%S\'")) // Method 1: Calling the to_timestamp method on a column\n .project(to_timestamp("visit_time_stamp", "\'%Y-%m-%d %H:%M:%S\'")) // Method 2: Using the to_timestamp function directly\n .execute(glue)\n .await;\n')))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/ae3eef3e.eb463894.js b/docs/0.16.0/assets/js/ae3eef3e.eb463894.js new file mode 100644 index 00000000..dc8a5502 --- /dev/null +++ b/docs/0.16.0/assets/js/ae3eef3e.eb463894.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[2591],{5680:(e,n,t)=>{t.d(n,{xA:()=>c,yg:()=>g});var r=t(6540);function a(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function o(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function l(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?o(Object(t),!0).forEach((function(n){a(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):o(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function i(e,n){if(null==e)return{};var t,r,a=function(e,n){if(null==e)return{};var t,r,a={},o=Object.keys(e);for(r=0;r<o.length;r++)t=o[r],n.indexOf(t)>=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r<o.length;r++)t=o[r],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var s=r.createContext({}),u=function(e){var n=r.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):l(l({},n),e)),t},c=function(e){var n=u(e.components);return r.createElement(s.Provider,{value:n},e.children)},p="mdxType",m={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},f=r.forwardRef((function(e,n){var t=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,c=i(e,["components","mdxType","originalType","parentName"]),p=u(t),f=a,g=p["".concat(s,".").concat(f)]||p[f]||m[f]||o;return t?r.createElement(g,l(l({ref:n},c),{},{components:t})):r.createElement(g,l({ref:n},c))}));function g(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var o=t.length,l=new Array(o);l[0]=f;var i={};for(var s in n)hasOwnProperty.call(n,s)&&(i[s]=n[s]);i.originalType=e,i[p]="string"==typeof e?e:a,l[1]=i;for(var u=2;u<o;u++)l[u]=t[u];return r.createElement.apply(null,l)}return r.createElement.apply(null,t)}f.displayName="MDXCreateElement"},4060:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>s,contentTitle:()=>l,default:()=>m,frontMatter:()=>o,metadata:()=>i,toc:()=>u});var r=t(8168),a=(t(6540),t(5680));const o={},l="LN",i={unversionedId:"sql-syntax/functions/math/ln",id:"sql-syntax/functions/math/ln",title:"LN",description:"The LN function is used to calculate the natural logarithm (base e) of a number. It takes a single FLOAT or INTEGER argument and returns a FLOAT value representing the natural logarithm of the given number.",source:"@site/docs/sql-syntax/functions/math/ln.md",sourceDirName:"sql-syntax/functions/math",slug:"/sql-syntax/functions/math/ln",permalink:"/docs/0.16.0/sql-syntax/functions/math/ln",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"LCM",permalink:"/docs/0.16.0/sql-syntax/functions/math/lcm"},next:{title:"LOG",permalink:"/docs/0.16.0/sql-syntax/functions/math/log"}},s={},u=[{value:"Example",id:"example",level:2},{value:"Errors",id:"errors",level:2}],c={toc:u},p="wrapper";function m(e){let{components:n,...t}=e;return(0,a.yg)(p,(0,r.A)({},c,t,{components:n,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"ln"},"LN"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"LN")," function is used to calculate the natural logarithm (base ",(0,a.yg)("inlineCode",{parentName:"p"},"e"),") of a number. It takes a single FLOAT or INTEGER argument and returns a FLOAT value representing the natural logarithm of the given number."),(0,a.yg)("h2",{id:"example"},"Example"),(0,a.yg)("p",null,"The following example demonstrates the usage of the ",(0,a.yg)("inlineCode",{parentName:"p"},"LN")," function in a SQL query:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE SingleItem (id INTEGER DEFAULT LN(10));\n\nINSERT INTO SingleItem VALUES (0);\n\nSELECT\n LN(64.0) as ln1,\n LN(0.04) as ln2\nFROM SingleItem;\n")),(0,a.yg)("p",null,"This will return the following result:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre"},"ln1 | ln2\n--------+-------------------\n4.1589 | -3.2189\n")),(0,a.yg)("h2",{id:"errors"},"Errors"),(0,a.yg)("ol",null,(0,a.yg)("li",{parentName:"ol"},"If the argument is not of FLOAT or INTEGER type, a ",(0,a.yg)("inlineCode",{parentName:"li"},"FunctionRequiresFloatValue")," error will be raised."),(0,a.yg)("li",{parentName:"ol"},"If the number of arguments provided to the function is not equal to 1, a ",(0,a.yg)("inlineCode",{parentName:"li"},"FunctionArgsLengthNotMatching")," error will be raised.")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/ae967838.0bc2b7aa.js b/docs/0.16.0/assets/js/ae967838.0bc2b7aa.js new file mode 100644 index 00000000..cfa2de7b --- /dev/null +++ b/docs/0.16.0/assets/js/ae967838.0bc2b7aa.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[9876],{5680:(e,t,r)=>{r.d(t,{xA:()=>c,yg:()=>m});var n=r(6540);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function l(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function s(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?l(Object(r),!0).forEach((function(t){a(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):l(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function i(e,t){if(null==e)return{};var r,n,a=function(e,t){if(null==e)return{};var r,n,a={},l=Object.keys(e);for(n=0;n<l.length;n++)r=l[n],t.indexOf(r)>=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(n=0;n<l.length;n++)r=l[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var o=n.createContext({}),u=function(e){var t=n.useContext(o),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},c=function(e){var t=u(e.components);return n.createElement(o.Provider,{value:t},e.children)},p="mdxType",y={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},g=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,l=e.originalType,o=e.parentName,c=i(e,["components","mdxType","originalType","parentName"]),p=u(r),g=a,m=p["".concat(o,".").concat(g)]||p[g]||y[g]||l;return r?n.createElement(m,s(s({ref:t},c),{},{components:r})):n.createElement(m,s({ref:t},c))}));function m(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var l=r.length,s=new Array(l);s[0]=g;var i={};for(var o in t)hasOwnProperty.call(t,o)&&(i[o]=t[o]);i.originalType=e,i[p]="string"==typeof e?e:a,s[1]=i;for(var u=2;u<l;u++)s[u]=r[u];return n.createElement.apply(null,s)}return n.createElement.apply(null,r)}g.displayName="MDXCreateElement"},9947:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>o,contentTitle:()=>s,default:()=>y,frontMatter:()=>l,metadata:()=>i,toc:()=>u});var n=r(8168),a=(r(6540),r(5680));const l={},s="REVERSE",i={unversionedId:"sql-syntax/functions/text/reverse",id:"sql-syntax/functions/text/reverse",title:"REVERSE",description:"The REVERSE function in SQL is used to reverse a string.",source:"@site/docs/sql-syntax/functions/text/reverse.md",sourceDirName:"sql-syntax/functions/text",slug:"/sql-syntax/functions/text/reverse",permalink:"/docs/0.16.0/sql-syntax/functions/text/reverse",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"REPEAT",permalink:"/docs/0.16.0/sql-syntax/functions/text/repeat"},next:{title:"RIGHT",permalink:"/docs/0.16.0/sql-syntax/functions/text/right"}},o={},u=[{value:"Syntax",id:"syntax",level:2},{value:"Parameters",id:"parameters",level:2},{value:"Return Value",id:"return-value",level:2},{value:"Errors",id:"errors",level:2},{value:"Examples",id:"examples",level:2}],c={toc:u},p="wrapper";function y(e){let{components:t,...r}=e;return(0,a.yg)(p,(0,n.A)({},c,r,{components:t,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"reverse"},"REVERSE"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"REVERSE")," function in SQL is used to reverse a string."),(0,a.yg)("h2",{id:"syntax"},"Syntax"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"REVERSE(string)\n")),(0,a.yg)("h2",{id:"parameters"},"Parameters"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"string"),": The string to be reversed.")),(0,a.yg)("h2",{id:"return-value"},"Return Value"),(0,a.yg)("p",null,"The function returns a string which is the reverse of the input string."),(0,a.yg)("h2",{id:"errors"},"Errors"),(0,a.yg)("p",null,"If the parameter is not a string value, a ",(0,a.yg)("inlineCode",{parentName:"p"},"EvaluateError::FunctionRequiresStringValue")," error will be returned."),(0,a.yg)("h2",{id:"examples"},"Examples"),(0,a.yg)("p",null,"Consider a table ",(0,a.yg)("inlineCode",{parentName:"p"},"Item")," created and filled with the following data:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE Item (name TEXT);\nINSERT INTO Item VALUES ('Let''s meet');\n")),(0,a.yg)("p",null,"You can use the ",(0,a.yg)("inlineCode",{parentName:"p"},"REVERSE")," function to reverse the ",(0,a.yg)("inlineCode",{parentName:"p"},"name")," values:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT REVERSE(name) AS test FROM Item;\n")),(0,a.yg)("p",null,"This will return:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre"},"teem s'teL\n")),(0,a.yg)("p",null,"The 'Let''s meet' string is reversed as 'teem s'teL'."))}y.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/afebe5f1.5fe2a23f.js b/docs/0.16.0/assets/js/afebe5f1.5fe2a23f.js new file mode 100644 index 00000000..f2945593 --- /dev/null +++ b/docs/0.16.0/assets/js/afebe5f1.5fe2a23f.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[1838],{5680:(e,t,n)=>{n.d(t,{xA:()=>c,yg:()=>f});var r=n(6540);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function l(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?a(Object(n),!0).forEach((function(t){o(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):a(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function i(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},a=Object.keys(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=r.createContext({}),u=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},c=function(e){var t=u(e.components);return r.createElement(s.Provider,{value:t},e.children)},p="mdxType",g={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,s=e.parentName,c=i(e,["components","mdxType","originalType","parentName"]),p=u(n),m=o,f=p["".concat(s,".").concat(m)]||p[m]||g[m]||a;return n?r.createElement(f,l(l({ref:t},c),{},{components:n})):r.createElement(f,l({ref:t},c))}));function f(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,l=new Array(a);l[0]=m;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i[p]="string"==typeof e?e:o,l[1]=i;for(var u=2;u<a;u++)l[u]=n[u];return r.createElement.apply(null,l)}return r.createElement.apply(null,n)}m.displayName="MDXCreateElement"},3927:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>g,frontMatter:()=>a,metadata:()=>i,toc:()=>u});var r=n(8168),o=(n(6540),n(5680));const a={},l="LOG10",i={unversionedId:"sql-syntax/functions/math/log10",id:"sql-syntax/functions/math/log10",title:"LOG10",description:"The LOG10 function is used to calculate the base-10 logarithm of a number. It takes a single FLOAT or INTEGER argument and returns a FLOAT value representing the base-10 logarithm of the given number.",source:"@site/docs/sql-syntax/functions/math/log10.md",sourceDirName:"sql-syntax/functions/math",slug:"/sql-syntax/functions/math/log10",permalink:"/docs/0.16.0/sql-syntax/functions/math/log10",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"LOG",permalink:"/docs/0.16.0/sql-syntax/functions/math/log"},next:{title:"LOG2",permalink:"/docs/0.16.0/sql-syntax/functions/math/log2"}},s={},u=[{value:"Example",id:"example",level:2},{value:"Errors",id:"errors",level:2}],c={toc:u},p="wrapper";function g(e){let{components:t,...n}=e;return(0,o.yg)(p,(0,r.A)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,o.yg)("h1",{id:"log10"},"LOG10"),(0,o.yg)("p",null,"The ",(0,o.yg)("inlineCode",{parentName:"p"},"LOG10")," function is used to calculate the base-10 logarithm of a number. It takes a single FLOAT or INTEGER argument and returns a FLOAT value representing the base-10 logarithm of the given number."),(0,o.yg)("h2",{id:"example"},"Example"),(0,o.yg)("p",null,"The following example demonstrates the usage of the ",(0,o.yg)("inlineCode",{parentName:"p"},"LOG10")," function in a SQL query:"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE SingleItem (id INTEGER DEFAULT LOG10(100));\n\nINSERT INTO SingleItem VALUES (0);\n\nSELECT\n LOG10(64.0) as log10_1,\n LOG10(0.04) as log10_2\nFROM SingleItem;\n")),(0,o.yg)("p",null,"This will return the following result:"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre"},"log10_1 | log10_2\n--------+-------------------\n1.8062 | -1.3979\n")),(0,o.yg)("h2",{id:"errors"},"Errors"),(0,o.yg)("ol",null,(0,o.yg)("li",{parentName:"ol"},"If the argument is not of FLOAT or INTEGER type, a ",(0,o.yg)("inlineCode",{parentName:"li"},"FunctionRequiresFloatValue")," error will be raised."),(0,o.yg)("li",{parentName:"ol"},"If the number of arguments provided to the function is not equal to 1, a ",(0,o.yg)("inlineCode",{parentName:"li"},"FunctionArgsLengthNotMatching")," error will be raised.")))}g.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/aff456d7.8f09df74.js b/docs/0.16.0/assets/js/aff456d7.8f09df74.js new file mode 100644 index 00000000..77b951e6 --- /dev/null +++ b/docs/0.16.0/assets/js/aff456d7.8f09df74.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[2710],{5680:(e,t,n)=>{n.d(t,{xA:()=>p,yg:()=>m});var a=n(6540);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function l(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function i(e,t){if(null==e)return{};var n,a,r=function(e,t){if(null==e)return{};var n,a,r={},o=Object.keys(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var c=a.createContext({}),s=function(e){var t=a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},p=function(e){var t=s(e.components);return a.createElement(c.Provider,{value:t},e.children)},u="mdxType",y={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},g=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,c=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),u=s(n),g=r,m=u["".concat(c,".").concat(g)]||u[g]||y[g]||o;return n?a.createElement(m,l(l({ref:t},p),{},{components:n})):a.createElement(m,l({ref:t},p))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,l=new Array(o);l[0]=g;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i[u]="string"==typeof e?e:r,l[1]=i;for(var s=2;s<o;s++)l[s]=n[s];return a.createElement.apply(null,l)}return a.createElement.apply(null,n)}g.displayName="MDXCreateElement"},4685:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>l,default:()=>y,frontMatter:()=>o,metadata:()=>i,toc:()=>s});var a=n(8168),r=(n(6540),n(5680));const o={},l="CALC_DISTANCE",i={unversionedId:"sql-syntax/functions/geometry/calc-distance",id:"sql-syntax/functions/geometry/calc-distance",title:"CALC_DISTANCE",description:"The CALC_DISTANCE function is used to calculate the Euclidean distance between two Point type geographical coordinates.",source:"@site/docs/sql-syntax/functions/geometry/calc-distance.md",sourceDirName:"sql-syntax/functions/geometry",slug:"/sql-syntax/functions/geometry/calc-distance",permalink:"/docs/0.16.0/sql-syntax/functions/geometry/calc-distance",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:'SQL Function - "SPLICE"',permalink:"/docs/0.16.0/sql-syntax/functions/list-map/splice"},next:{title:"GET_X",permalink:"/docs/0.16.0/sql-syntax/functions/geometry/get-x"}},c={},s=[{value:"Syntax",id:"syntax",level:2},{value:"Examples",id:"examples",level:2},{value:"Example 1: Calculate the distance between two points",id:"example-1-calculate-the-distance-between-two-points",level:3},{value:"Errors",id:"errors",level:2}],p={toc:s},u="wrapper";function y(e){let{components:t,...n}=e;return(0,r.yg)(u,(0,a.A)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,r.yg)("h1",{id:"calc_distance"},"CALC_DISTANCE"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"CALC_DISTANCE")," function is used to calculate the Euclidean distance between two ",(0,r.yg)("inlineCode",{parentName:"p"},"Point")," type geographical coordinates."),(0,r.yg)("h2",{id:"syntax"},"Syntax"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"CALC_DISTANCE(point1, point2)\n")),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},"Parameters:")),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"point1"),": The first geographical coordinate of type ",(0,r.yg)("inlineCode",{parentName:"li"},"Point"),"."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"point2"),": The second geographical coordinate of type ",(0,r.yg)("inlineCode",{parentName:"li"},"Point"),".")),(0,r.yg)("h2",{id:"examples"},"Examples"),(0,r.yg)("p",null,"Consider the following table ",(0,r.yg)("inlineCode",{parentName:"p"},"Foo"),":"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE Foo (\n geo1 Point,\n geo2 Point,\n bar Float\n);\n")),(0,r.yg)("p",null,"With the following data:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO Foo VALUES (POINT(0.3134, 3.156), POINT(1.415, 3.231), 3);\n")),(0,r.yg)("h3",{id:"example-1-calculate-the-distance-between-two-points"},"Example 1: Calculate the distance between two points"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT CALC_DISTANCE(geo1, geo2) AS georesult FROM Foo;\n")),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},"Result:")),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},"georesult"))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},"1.104150152832485")))),(0,r.yg)("h2",{id:"errors"},"Errors"),(0,r.yg)("ol",null,(0,r.yg)("li",{parentName:"ol"},"If the number of arguments is not 2, a ",(0,r.yg)("inlineCode",{parentName:"li"},"FunctionArgsLengthNotMatching")," error will be thrown."),(0,r.yg)("li",{parentName:"ol"},"If any of the arguments are not of type ",(0,r.yg)("inlineCode",{parentName:"li"},"Point"),", a ",(0,r.yg)("inlineCode",{parentName:"li"},"FunctionRequiresPointValue")," error will be thrown."),(0,r.yg)("li",{parentName:"ol"},"If any of the arguments are ",(0,r.yg)("inlineCode",{parentName:"li"},"NULL"),", the result will be ",(0,r.yg)("inlineCode",{parentName:"li"},"NULL"),".")))}y.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/b209ab8a.cf366253.js b/docs/0.16.0/assets/js/b209ab8a.cf366253.js new file mode 100644 index 00000000..04755022 --- /dev/null +++ b/docs/0.16.0/assets/js/b209ab8a.cf366253.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[3386],{5680:(e,t,r)=>{r.d(t,{xA:()=>c,yg:()=>f});var o=r(6540);function n(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,o)}return r}function s(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?i(Object(r),!0).forEach((function(t){n(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):i(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function a(e,t){if(null==e)return{};var r,o,n=function(e,t){if(null==e)return{};var r,o,n={},i=Object.keys(e);for(o=0;o<i.length;o++)r=i[o],t.indexOf(r)>=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o<i.length;o++)r=i[o],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var l=o.createContext({}),u=function(e){var t=o.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},c=function(e){var t=u(e.components);return o.createElement(l.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},g=o.forwardRef((function(e,t){var r=e.components,n=e.mdxType,i=e.originalType,l=e.parentName,c=a(e,["components","mdxType","originalType","parentName"]),p=u(r),g=n,f=p["".concat(l,".").concat(g)]||p[g]||d[g]||i;return r?o.createElement(f,s(s({ref:t},c),{},{components:r})):o.createElement(f,s({ref:t},c))}));function f(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var i=r.length,s=new Array(i);s[0]=g;var a={};for(var l in t)hasOwnProperty.call(t,l)&&(a[l]=t[l]);a.originalType=e,a[p]="string"==typeof e?e:n,s[1]=a;for(var u=2;u<i;u++)s[u]=r[u];return o.createElement.apply(null,s)}return o.createElement.apply(null,r)}g.displayName="MDXCreateElement"},6719:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>s,default:()=>d,frontMatter:()=>i,metadata:()=>a,toc:()=>u});var o=r(8168),n=(r(6540),r(5680));const i={sidebar_position:1},s="Introduction",a={unversionedId:"storages/intro",id:"storages/intro",title:"Introduction",description:"GlueSQL is not only suitable for use as a conventional database, but one of its key features is the ability for anyone to easily adapt SQL and the AST Builder to their desired file or storage system. This adaptability is achieved through the following topics covered in this section:",source:"@site/docs/storages/intro.md",sourceDirName:"storages",slug:"/storages/intro",permalink:"/docs/0.16.0/storages/intro",draft:!1,tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"autoSidebar",previous:{title:"Unique Identifier",permalink:"/docs/0.16.0/ast-builder/functions/others/unique-identifier"},next:{title:"Composite Storage",permalink:"/docs/0.16.0/storages/supported-storages/composite-storage"}},l={},u=[{value:"Supported Storages",id:"supported-storages",level:2},{value:"Developing Custom Storages",id:"developing-custom-storages",level:2},{value:"Exploring the Storages Section",id:"exploring-the-storages-section",level:2}],c={toc:u},p="wrapper";function d(e){let{components:t,...r}=e;return(0,n.yg)(p,(0,o.A)({},c,r,{components:t,mdxType:"MDXLayout"}),(0,n.yg)("h1",{id:"introduction"},"Introduction"),(0,n.yg)("p",null,"GlueSQL is not only suitable for use as a conventional database, but one of its key features is the ability for anyone to easily adapt SQL and the AST Builder to their desired file or storage system. This adaptability is achieved through the following topics covered in this section:"),(0,n.yg)("h2",{id:"supported-storages"},"Supported Storages"),(0,n.yg)("p",null,"GlueSQL provides a variety of reference storages out of the box, ranging from simple in-memory storage to key-value databases, log file-based storage like JSON & JSONL, and even Web Storage and IndexedDB supported by web browsers."),(0,n.yg)("h2",{id:"developing-custom-storages"},"Developing Custom Storages"),(0,n.yg)("p",null,"GlueSQL offers an easy-to-understand and implement interface for custom storage development. By implementing the corresponding interface, developers can have SQL and the AST Builder automatically support their custom storage. "),(0,n.yg)("p",null,"Verification of custom storage implementation is also straightforward using GlueSQL's test-suite, which allows developers to easily test their implementation and fix any issues found during the process. With a line coverage of nearly 99% in the GlueSQL project's core code, custom storage developers can complete the development and verification process simply by passing all the test-suite cases."),(0,n.yg)("h2",{id:"exploring-the-storages-section"},"Exploring the Storages Section"),(0,n.yg)("p",null,"In the Storages section, you will find detailed information about the reference storages currently supported by GlueSQL, as well as guidelines for developing custom storages and what needs to be done to implement them."),(0,n.yg)("p",null,"Together, these resources make it easy to utilize and adapt GlueSQL for a variety of storage systems."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/b3de9677.5c877865.js b/docs/0.16.0/assets/js/b3de9677.5c877865.js new file mode 100644 index 00000000..c1028607 --- /dev/null +++ b/docs/0.16.0/assets/js/b3de9677.5c877865.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[7319],{5680:(e,t,n)=>{n.d(t,{xA:()=>s,yg:()=>y});var r=n(6540);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function u(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},o=Object.keys(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=r.createContext({}),g=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},s=function(e){var t=g(e.components);return r.createElement(l.Provider,{value:t},e.children)},c="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,l=e.parentName,s=u(e,["components","mdxType","originalType","parentName"]),c=g(n),d=a,y=c["".concat(l,".").concat(d)]||c[d]||p[d]||o;return n?r.createElement(y,i(i({ref:t},s),{},{components:n})):r.createElement(y,i({ref:t},s))}));function y(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=d;var u={};for(var l in t)hasOwnProperty.call(t,l)&&(u[l]=t[l]);u.originalType=e,u[c]="string"==typeof e?e:a,i[1]=u;for(var g=2;g<o;g++)i[g]=n[g];return r.createElement.apply(null,i)}return r.createElement.apply(null,n)}d.displayName="MDXCreateElement"},1624:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>p,frontMatter:()=>o,metadata:()=>u,toc:()=>g});var r=n(8168),a=(n(6540),n(5680));const o={},i="Data Aggregation",u={unversionedId:"ast-builder/statements/querying/data-aggregation",id:"ast-builder/statements/querying/data-aggregation",title:"Data Aggregation",description:"The AST Builder API in GlueSQL allows you to construct SQL queries programmatically. This page provides an introduction to data aggregation using the AST Builder API.",source:"@site/docs/ast-builder/statements/querying/data-aggregation.md",sourceDirName:"ast-builder/statements/querying",slug:"/ast-builder/statements/querying/data-aggregation",permalink:"/docs/0.16.0/ast-builder/statements/querying/data-aggregation",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"Creating Derived Subqueries",permalink:"/docs/0.16.0/ast-builder/statements/querying/creating-derived-subqueries"},next:{title:"Data Injection",permalink:"/docs/0.16.0/ast-builder/statements/querying/data-injection"}},l={},g=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Grouping and Counting",id:"grouping-and-counting",level:2},{value:"Filtering Groups with HAVING",id:"filtering-groups-with-having",level:2}],s={toc:g},c="wrapper";function p(e){let{components:t,...n}=e;return(0,a.yg)(c,(0,r.A)({},s,n,{components:t,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"data-aggregation"},"Data Aggregation"),(0,a.yg)("p",null,"The AST Builder API in GlueSQL allows you to construct SQL queries programmatically. This page provides an introduction to data aggregation using the AST Builder API."),(0,a.yg)("h2",{id:"prerequisites"},"Prerequisites"),(0,a.yg)("p",null,'Before we explore data aggregation examples, let\'s set up a sample table called "User" with the following columns: "id" (INT), "name" (TEXT), and "age" (INT).'),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE User (\n id INT,\n name TEXT,\n age INT\n);\n")),(0,a.yg)("p",null,"We will use this table for the subsequent examples."),(0,a.yg)("h2",{id:"grouping-and-counting"},"Grouping and Counting"),(0,a.yg)("p",null,"To group records by a specific column and count the number of occurrences in each group, you can use the AST Builder's ",(0,a.yg)("inlineCode",{parentName:"p"},"group_by()")," and ",(0,a.yg)("inlineCode",{parentName:"p"},"project()")," methods."),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-rust"},'table("User")\n .select()\n .group_by("age")\n .project("age, count(*)")\n .execute(glue);\n')),(0,a.yg)("p",null,'The above code groups the records in the "User" table by the "age" column and returns the age value along with the count of occurrences in each group. The result would be:'),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre"},"age | count(*)\n----|---------\n20 | 1\n30 | 2\n50 | 2\n")),(0,a.yg)("h2",{id:"filtering-groups-with-having"},"Filtering Groups with HAVING"),(0,a.yg)("p",null,"You can further filter the groups based on specific conditions using the ",(0,a.yg)("inlineCode",{parentName:"p"},"having()")," method. The ",(0,a.yg)("inlineCode",{parentName:"p"},"having()")," method allows you to apply conditions to the grouped data."),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-rust"},'table("User")\n .select()\n .group_by("age")\n .having("count(*) > 1")\n .project("age, count(*)")\n .execute(glue);\n')),(0,a.yg)("p",null,'The above code groups the records in the "User" table by the "age" column, but it only includes groups where the count of occurrences is greater than 1. The result would be:'),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre"},"age | count(*)\n----|---------\n30 | 2\n50 | 2\n")),(0,a.yg)("p",null,"This concludes the introduction to data aggregation using the AST Builder API in GlueSQL. You can leverage these methods to perform various aggregations and analyze your data effectively."))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/b57ca7d5.032ee46f.js b/docs/0.16.0/assets/js/b57ca7d5.032ee46f.js new file mode 100644 index 00000000..68dc90ac --- /dev/null +++ b/docs/0.16.0/assets/js/b57ca7d5.032ee46f.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[7879],{5680:(e,t,n)=>{n.d(t,{xA:()=>p,yg:()=>g});var r=n(6540);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function l(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function o(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},i=Object.keys(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),u=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},p=function(e){var t=u(e.components);return r.createElement(s.Provider,{value:t},e.children)},c="mdxType",y={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,s=e.parentName,p=o(e,["components","mdxType","originalType","parentName"]),c=u(n),m=a,g=c["".concat(s,".").concat(m)]||c[m]||y[m]||i;return n?r.createElement(g,l(l({ref:t},p),{},{components:n})):r.createElement(g,l({ref:t},p))}));function g(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,l=new Array(i);l[0]=m;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[c]="string"==typeof e?e:a,l[1]=o;for(var u=2;u<i;u++)l[u]=n[u];return r.createElement.apply(null,l)}return r.createElement.apply(null,n)}m.displayName="MDXCreateElement"},4374:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>y,frontMatter:()=>i,metadata:()=>o,toc:()=>u});var r=n(8168),a=(n(6540),n(5680));const i={},l="REPEAT",o={unversionedId:"sql-syntax/functions/text/repeat",id:"sql-syntax/functions/text/repeat",title:"REPEAT",description:"The REPEAT function in SQL is used to repeat a string for a specified number of times.",source:"@site/docs/sql-syntax/functions/text/repeat.md",sourceDirName:"sql-syntax/functions/text",slug:"/sql-syntax/functions/text/repeat",permalink:"/docs/0.16.0/sql-syntax/functions/text/repeat",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"POSITION",permalink:"/docs/0.16.0/sql-syntax/functions/text/position"},next:{title:"REVERSE",permalink:"/docs/0.16.0/sql-syntax/functions/text/reverse"}},s={},u=[{value:"Syntax",id:"syntax",level:2},{value:"Parameters",id:"parameters",level:2},{value:"Return Value",id:"return-value",level:2},{value:"Errors",id:"errors",level:2},{value:"Examples",id:"examples",level:2}],p={toc:u},c="wrapper";function y(e){let{components:t,...n}=e;return(0,a.yg)(c,(0,r.A)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"repeat"},"REPEAT"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"REPEAT")," function in SQL is used to repeat a string for a specified number of times."),(0,a.yg)("h2",{id:"syntax"},"Syntax"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"REPEAT(string, number)\n")),(0,a.yg)("h2",{id:"parameters"},"Parameters"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"string"),": The string to be repeated."),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"number"),": The number of times to repeat the string. ")),(0,a.yg)("h2",{id:"return-value"},"Return Value"),(0,a.yg)("p",null,"The function returns a string which is the concatenation of the input string repeated the specified number of times."),(0,a.yg)("h2",{id:"errors"},"Errors"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},"If the parameters are not in the correct format, a ",(0,a.yg)("inlineCode",{parentName:"li"},"TranslateError::FunctionArgsLengthNotMatching")," error will be returned. This function requires exactly two arguments."),(0,a.yg)("li",{parentName:"ul"},"If either ",(0,a.yg)("inlineCode",{parentName:"li"},"string")," or ",(0,a.yg)("inlineCode",{parentName:"li"},"number")," are not string values, a ",(0,a.yg)("inlineCode",{parentName:"li"},"EvaluateError::FunctionRequiresStringValue")," error will be returned.")),(0,a.yg)("h2",{id:"examples"},"Examples"),(0,a.yg)("p",null,"Consider a table ",(0,a.yg)("inlineCode",{parentName:"p"},"Item")," created and filled with the following data:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE Item (name TEXT);\nINSERT INTO Item VALUES ('hello');\n")),(0,a.yg)("p",null,"You can use the ",(0,a.yg)("inlineCode",{parentName:"p"},"REPEAT")," function to repeat the ",(0,a.yg)("inlineCode",{parentName:"p"},"name")," values:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT REPEAT(name, 2) AS test FROM Item;\n")),(0,a.yg)("p",null,"This will return:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre"},"hellohello\n")),(0,a.yg)("p",null,"The 'hello' string is repeated twice as specified by the second parameter to the ",(0,a.yg)("inlineCode",{parentName:"p"},"REPEAT")," function."))}y.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/b6bceaff.19fa54f6.js b/docs/0.16.0/assets/js/b6bceaff.19fa54f6.js new file mode 100644 index 00000000..5fc4d269 --- /dev/null +++ b/docs/0.16.0/assets/js/b6bceaff.19fa54f6.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[2012],{5680:(e,r,t)=>{t.d(r,{xA:()=>u,yg:()=>y});var n=t(6540);function o(e,r,t){return r in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function a(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);r&&(n=n.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),t.push.apply(t,n)}return t}function i(e){for(var r=1;r<arguments.length;r++){var t=null!=arguments[r]?arguments[r]:{};r%2?a(Object(t),!0).forEach((function(r){o(e,r,t[r])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):a(Object(t)).forEach((function(r){Object.defineProperty(e,r,Object.getOwnPropertyDescriptor(t,r))}))}return e}function c(e,r){if(null==e)return{};var t,n,o=function(e,r){if(null==e)return{};var t,n,o={},a=Object.keys(e);for(n=0;n<a.length;n++)t=a[n],r.indexOf(t)>=0||(o[t]=e[t]);return o}(e,r);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n<a.length;n++)t=a[n],r.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var s=n.createContext({}),l=function(e){var r=n.useContext(s),t=r;return e&&(t="function"==typeof e?e(r):i(i({},r),e)),t},u=function(e){var r=l(e.components);return n.createElement(s.Provider,{value:r},e.children)},p="mdxType",f={inlineCode:"code",wrapper:function(e){var r=e.children;return n.createElement(n.Fragment,{},r)}},d=n.forwardRef((function(e,r){var t=e.components,o=e.mdxType,a=e.originalType,s=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),p=l(t),d=o,y=p["".concat(s,".").concat(d)]||p[d]||f[d]||a;return t?n.createElement(y,i(i({ref:r},u),{},{components:t})):n.createElement(y,i({ref:r},u))}));function y(e,r){var t=arguments,o=r&&r.mdxType;if("string"==typeof e||o){var a=t.length,i=new Array(a);i[0]=d;var c={};for(var s in r)hasOwnProperty.call(r,s)&&(c[s]=r[s]);c.originalType=e,c[p]="string"==typeof e?e:o,i[1]=c;for(var l=2;l<a;l++)i[l]=t[l];return n.createElement.apply(null,i)}return n.createElement.apply(null,t)}d.displayName="MDXCreateElement"},535:(e,r,t)=>{t.r(r),t.d(r,{assets:()=>s,contentTitle:()=>i,default:()=>f,frontMatter:()=>a,metadata:()=>c,toc:()=>l});var n=t(8168),o=(t(6540),t(5680));const a={},i="Value Checking",c={unversionedId:"ast-builder/expressions/value-checking",id:"ast-builder/expressions/value-checking",title:"Value Checking",description:"Todo",source:"@site/docs/ast-builder/expressions/value-checking.md",sourceDirName:"ast-builder/expressions",slug:"/ast-builder/expressions/value-checking",permalink:"/docs/0.16.0/ast-builder/expressions/value-checking",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"Pattern Matching",permalink:"/docs/0.16.0/ast-builder/expressions/pattern-matching"},next:{title:"Case Conversion",permalink:"/docs/0.16.0/ast-builder/functions/text/case-conversion"}},s={},l=[{value:"Todo",id:"todo",level:2}],u={toc:l},p="wrapper";function f(e){let{components:r,...t}=e;return(0,o.yg)(p,(0,n.A)({},u,t,{components:r,mdxType:"MDXLayout"}),(0,o.yg)("h1",{id:"value-checking"},"Value Checking"),(0,o.yg)("h2",{id:"todo"},"Todo"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre"},"- BETWEEN: Checks if a value is within a range of values.\n- IN_LIST: Checks if a value is within a list of values.\n- IS_NULL: Checks if a value is NULL.\n- EXISTS: Checks if a subquery returns any rows.\n")))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/b7661aba.2998c510.js b/docs/0.16.0/assets/js/b7661aba.2998c510.js new file mode 100644 index 00000000..8cb31de6 --- /dev/null +++ b/docs/0.16.0/assets/js/b7661aba.2998c510.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[3783],{5680:(e,t,n)=>{n.d(t,{xA:()=>p,yg:()=>m});var r=n(6540);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?l(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):l(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function o(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},l=Object.keys(e);for(r=0;r<l.length;r++)n=l[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(r=0;r<l.length;r++)n=l[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),c=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=c(e.components);return r.createElement(s.Provider,{value:t},e.children)},u="mdxType",y={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},g=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,l=e.originalType,s=e.parentName,p=o(e,["components","mdxType","originalType","parentName"]),u=c(n),g=a,m=u["".concat(s,".").concat(g)]||u[g]||y[g]||l;return n?r.createElement(m,i(i({ref:t},p),{},{components:n})):r.createElement(m,i({ref:t},p))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var l=n.length,i=new Array(l);i[0]=g;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[u]="string"==typeof e?e:a,i[1]=o;for(var c=2;c<l;c++)i[c]=n[c];return r.createElement.apply(null,i)}return r.createElement.apply(null,n)}g.displayName="MDXCreateElement"},1749:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>y,frontMatter:()=>l,metadata:()=>o,toc:()=>c});var r=n(8168),a=(n(6540),n(5680));const l={},i="UPPER",o={unversionedId:"sql-syntax/functions/text/upper",id:"sql-syntax/functions/text/upper",title:"UPPER",description:"The UPPER function in SQL converts all lowercase alphabetic characters in a specified string to uppercase.",source:"@site/docs/sql-syntax/functions/text/upper.md",sourceDirName:"sql-syntax/functions/text",slug:"/sql-syntax/functions/text/upper",permalink:"/docs/0.16.0/sql-syntax/functions/text/upper",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"TRIM",permalink:"/docs/0.16.0/sql-syntax/functions/text/trim"},next:{title:"ABS",permalink:"/docs/0.16.0/sql-syntax/functions/math/abs"}},s={},c=[{value:"Syntax",id:"syntax",level:2},{value:"Parameters",id:"parameters",level:2},{value:"Return Value",id:"return-value",level:2},{value:"Errors",id:"errors",level:2},{value:"Examples",id:"examples",level:2}],p={toc:c},u="wrapper";function y(e){let{components:t,...n}=e;return(0,a.yg)(u,(0,r.A)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"upper"},"UPPER"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"UPPER")," function in SQL converts all lowercase alphabetic characters in a specified string to uppercase."),(0,a.yg)("h2",{id:"syntax"},"Syntax"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"UPPER(string)\n")),(0,a.yg)("h2",{id:"parameters"},"Parameters"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"string"),": The original string to convert.")),(0,a.yg)("h2",{id:"return-value"},"Return Value"),(0,a.yg)("p",null,"The function returns a new string that is the same as the original string, but with all lowercase characters converted to uppercase. Non-alphabetic characters in the string are unaffected."),(0,a.yg)("h2",{id:"errors"},"Errors"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},"If the ",(0,a.yg)("inlineCode",{parentName:"li"},"string")," argument is not a string, a ",(0,a.yg)("inlineCode",{parentName:"li"},"FunctionRequiresStringValue")," error will be returned.")),(0,a.yg)("h2",{id:"examples"},"Examples"),(0,a.yg)("p",null,"Consider a table ",(0,a.yg)("inlineCode",{parentName:"p"},"Item")," created and filled with the following data:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE Item (\n name TEXT\n);\nINSERT INTO Item VALUES ('abcd'), ('Abcd'), ('ABCD');\n")),(0,a.yg)("p",null,"You can use the ",(0,a.yg)("inlineCode",{parentName:"p"},"UPPER")," function to convert all ",(0,a.yg)("inlineCode",{parentName:"p"},"name")," values to uppercase:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT UPPER(name) AS upper_name FROM Item;\n")),(0,a.yg)("p",null,"This will return:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre"},"ABCD\nABCD\nABCD\n")),(0,a.yg)("p",null,"Note that the ",(0,a.yg)("inlineCode",{parentName:"p"},"UPPER")," function affects only alphabetic characters. Non-alphabetic characters in the string remain unchanged."))}y.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/b7da1136.344a5231.js b/docs/0.16.0/assets/js/b7da1136.344a5231.js new file mode 100644 index 00000000..51f1dfc2 --- /dev/null +++ b/docs/0.16.0/assets/js/b7da1136.344a5231.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[4602],{5680:(e,n,t)=>{t.d(n,{xA:()=>p,yg:()=>m});var r=t(6540);function a(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function l(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function i(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?l(Object(t),!0).forEach((function(n){a(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):l(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function o(e,n){if(null==e)return{};var t,r,a=function(e,n){if(null==e)return{};var t,r,a={},l=Object.keys(e);for(r=0;r<l.length;r++)t=l[r],n.indexOf(t)>=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(r=0;r<l.length;r++)t=l[r],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var s=r.createContext({}),u=function(e){var n=r.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},p=function(e){var n=u(e.components);return r.createElement(s.Provider,{value:n},e.children)},g="mdxType",y={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},c=r.forwardRef((function(e,n){var t=e.components,a=e.mdxType,l=e.originalType,s=e.parentName,p=o(e,["components","mdxType","originalType","parentName"]),g=u(t),c=a,m=g["".concat(s,".").concat(c)]||g[c]||y[c]||l;return t?r.createElement(m,i(i({ref:n},p),{},{components:t})):r.createElement(m,i({ref:n},p))}));function m(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var l=t.length,i=new Array(l);i[0]=c;var o={};for(var s in n)hasOwnProperty.call(n,s)&&(o[s]=n[s]);o.originalType=e,o[g]="string"==typeof e?e:a,i[1]=o;for(var u=2;u<l;u++)i[u]=t[u];return r.createElement.apply(null,i)}return r.createElement.apply(null,t)}c.displayName="MDXCreateElement"},7960:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>s,contentTitle:()=>i,default:()=>y,frontMatter:()=>l,metadata:()=>o,toc:()=>u});var r=t(8168),a=(t(6540),t(5680));const l={sidebar_position:3},i="LIMIT & OFFSET",o={unversionedId:"sql-syntax/statements/querying/limit",id:"sql-syntax/statements/querying/limit",title:"LIMIT & OFFSET",description:"LIMIT and OFFSET are SQL clauses that allow you to control the number of rows returned by a SELECT statement. They are particularly useful when you need to paginate or retrieve a specific portion of the result set.",source:"@site/docs/sql-syntax/statements/querying/limit.md",sourceDirName:"sql-syntax/statements/querying",slug:"/sql-syntax/statements/querying/limit",permalink:"/docs/0.16.0/sql-syntax/statements/querying/limit",draft:!1,tags:[],version:"current",sidebarPosition:3,frontMatter:{sidebar_position:3},sidebar:"autoSidebar",previous:{title:"JOIN",permalink:"/docs/0.16.0/sql-syntax/statements/querying/join"},next:{title:"Aggregation",permalink:"/docs/0.16.0/sql-syntax/statements/querying/aggregation"}},s={},u=[{value:"LIMIT",id:"limit",level:2},{value:"OFFSET",id:"offset",level:2},{value:"Examples",id:"examples",level:2},{value:"Using LIMIT",id:"using-limit",level:3},{value:"Using LIMIT and OFFSET",id:"using-limit-and-offset",level:3},{value:"Using OFFSET without LIMIT",id:"using-offset-without-limit",level:3}],p={toc:u},g="wrapper";function y(e){let{components:n,...t}=e;return(0,a.yg)(g,(0,r.A)({},p,t,{components:n,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"limit--offset"},"LIMIT & OFFSET"),(0,a.yg)("p",null,(0,a.yg)("inlineCode",{parentName:"p"},"LIMIT")," and ",(0,a.yg)("inlineCode",{parentName:"p"},"OFFSET")," are SQL clauses that allow you to control the number of rows returned by a ",(0,a.yg)("inlineCode",{parentName:"p"},"SELECT")," statement. They are particularly useful when you need to paginate or retrieve a specific portion of the result set."),(0,a.yg)("h2",{id:"limit"},"LIMIT"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"LIMIT")," clause restricts the number of rows returned by a query. The syntax for using ",(0,a.yg)("inlineCode",{parentName:"p"},"LIMIT")," is:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT columns FROM table_name\nLIMIT number_of_rows;\n")),(0,a.yg)("h2",{id:"offset"},"OFFSET"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"OFFSET")," clause is used in combination with ",(0,a.yg)("inlineCode",{parentName:"p"},"LIMIT")," to skip a specific number of rows before starting to return the rows. The syntax for using ",(0,a.yg)("inlineCode",{parentName:"p"},"OFFSET")," is:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT columns FROM table_name\nLIMIT number_of_rows\nOFFSET number_of_rows_to_skip;\n")),(0,a.yg)("p",null,"You can also use ",(0,a.yg)("inlineCode",{parentName:"p"},"OFFSET")," without ",(0,a.yg)("inlineCode",{parentName:"p"},"LIMIT"),":"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT columns FROM table_name\nOFFSET number_of_rows_to_skip;\n")),(0,a.yg)("h2",{id:"examples"},"Examples"),(0,a.yg)("p",null,"Consider the following ",(0,a.yg)("inlineCode",{parentName:"p"},"Test")," table:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE Test (\n id INTEGER\n);\n")),(0,a.yg)("p",null,"With the following records:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO Test VALUES (1), (2), (3), (4), (5), (6), (7), (8);\n")),(0,a.yg)("h3",{id:"using-limit"},"Using LIMIT"),(0,a.yg)("p",null,"Retrieve the first 3 rows from the ",(0,a.yg)("inlineCode",{parentName:"p"},"Test")," table:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT * FROM Test LIMIT 3;\n")),(0,a.yg)("p",null,"Result:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre"},"id\n---\n1\n2\n3\n")),(0,a.yg)("h3",{id:"using-limit-and-offset"},"Using LIMIT and OFFSET"),(0,a.yg)("p",null,"Retrieve the next 4 rows after the first 3 rows from the ",(0,a.yg)("inlineCode",{parentName:"p"},"Test")," table:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT * FROM Test LIMIT 4 OFFSET 3;\n")),(0,a.yg)("p",null,"Result:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre"},"id\n---\n4\n5\n6\n7\n")),(0,a.yg)("h3",{id:"using-offset-without-limit"},"Using OFFSET without LIMIT"),(0,a.yg)("p",null,"Retrieve all rows after the first 2 rows from the ",(0,a.yg)("inlineCode",{parentName:"p"},"Test")," table:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT * FROM Test OFFSET 2;\n")),(0,a.yg)("p",null,"Result:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre"},"id\n---\n3\n4\n5\n6\n7\n8\n")))}y.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/ba43b2d5.5ca14789.js b/docs/0.16.0/assets/js/ba43b2d5.5ca14789.js new file mode 100644 index 00000000..aff4e2b2 --- /dev/null +++ b/docs/0.16.0/assets/js/ba43b2d5.5ca14789.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[6554],{5680:(e,n,t)=>{t.d(n,{xA:()=>c,yg:()=>y});var a=t(6540);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function l(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function i(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?l(Object(t),!0).forEach((function(n){r(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):l(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function s(e,n){if(null==e)return{};var t,a,r=function(e,n){if(null==e)return{};var t,a,r={},l=Object.keys(e);for(a=0;a<l.length;a++)t=l[a],n.indexOf(t)>=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a<l.length;a++)t=l[a],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var u=a.createContext({}),o=function(e){var n=a.useContext(u),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},c=function(e){var n=o(e.components);return a.createElement(u.Provider,{value:n},e.children)},p="mdxType",m={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},g=a.forwardRef((function(e,n){var t=e.components,r=e.mdxType,l=e.originalType,u=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),p=o(t),g=r,y=p["".concat(u,".").concat(g)]||p[g]||m[g]||l;return t?a.createElement(y,i(i({ref:n},c),{},{components:t})):a.createElement(y,i({ref:n},c))}));function y(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var l=t.length,i=new Array(l);i[0]=g;var s={};for(var u in n)hasOwnProperty.call(n,u)&&(s[u]=n[u]);s.originalType=e,s[p]="string"==typeof e?e:r,i[1]=s;for(var o=2;o<l;o++)i[o]=t[o];return a.createElement.apply(null,i)}return a.createElement.apply(null,t)}g.displayName="MDXCreateElement"},6644:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>u,contentTitle:()=>i,default:()=>m,frontMatter:()=>l,metadata:()=>s,toc:()=>o});var a=t(8168),r=(t(6540),t(5680));const l={},i="ATAN",s={unversionedId:"sql-syntax/functions/math/atan",id:"sql-syntax/functions/math/atan",title:"ATAN",description:"The ATAN function is used to calculate the arctangent (inverse tangent) of a number. It takes a single numeric argument, and returns the arctangent of that number in radians.",source:"@site/docs/sql-syntax/functions/math/atan.md",sourceDirName:"sql-syntax/functions/math",slug:"/sql-syntax/functions/math/atan",permalink:"/docs/0.16.0/sql-syntax/functions/math/atan",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"ASIN",permalink:"/docs/0.16.0/sql-syntax/functions/math/asin"},next:{title:"CEIL",permalink:"/docs/0.16.0/sql-syntax/functions/math/ceil"}},u={},o=[{value:"Syntax",id:"syntax",level:2},{value:"Examples",id:"examples",level:2},{value:"Example 1: Using ATAN with float values",id:"example-1-using-atan-with-float-values",level:3},{value:"Example 2: Using ATAN with NULL values",id:"example-2-using-atan-with-null-values",level:3},{value:"Errors",id:"errors",level:2},{value:"Example 3: Using ATAN with non-numeric values",id:"example-3-using-atan-with-non-numeric-values",level:3},{value:"Example 4: Using ATAN with multiple arguments",id:"example-4-using-atan-with-multiple-arguments",level:3}],c={toc:o},p="wrapper";function m(e){let{components:n,...t}=e;return(0,r.yg)(p,(0,a.A)({},c,t,{components:n,mdxType:"MDXLayout"}),(0,r.yg)("h1",{id:"atan"},"ATAN"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"ATAN")," function is used to calculate the arctangent (inverse tangent) of a number. It takes a single numeric argument, and returns the arctangent of that number in radians."),(0,r.yg)("h2",{id:"syntax"},"Syntax"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"ATAN(value)\n")),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"value"),": A numeric expression for which the arctangent is to be calculated.")),(0,r.yg)("h2",{id:"examples"},"Examples"),(0,r.yg)("p",null,"Let's consider a table named ",(0,r.yg)("inlineCode",{parentName:"p"},"SingleItem")," with the following schema:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE SingleItem (id INTEGER);\n")),(0,r.yg)("p",null,"Insert a row into the ",(0,r.yg)("inlineCode",{parentName:"p"},"SingleItem")," table:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO SingleItem VALUES (0);\n")),(0,r.yg)("h3",{id:"example-1-using-atan-with-float-values"},"Example 1: Using ATAN with float values"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT ATAN(0.5) AS atan1, ATAN(1) AS atan2 FROM SingleItem;\n")),(0,r.yg)("p",null,"Result:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre"}," atan1 | atan2\n--------------+---------------\n 0.463647609 | 0.785398163\n")),(0,r.yg)("h3",{id:"example-2-using-atan-with-null-values"},"Example 2: Using ATAN with NULL values"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT ATAN(NULL) AS atan FROM SingleItem;\n")),(0,r.yg)("p",null,"Result:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre"}," atan\n-------\n (null)\n")),(0,r.yg)("h2",{id:"errors"},"Errors"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"ATAN")," function requires a numeric value as its argument. Using non-numeric values or more than one argument will result in an error."),(0,r.yg)("h3",{id:"example-3-using-atan-with-non-numeric-values"},"Example 3: Using ATAN with non-numeric values"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT ATAN('string') AS atan FROM SingleItem;\n")),(0,r.yg)("p",null,"Error: Function requires a numeric value."),(0,r.yg)("h3",{id:"example-4-using-atan-with-multiple-arguments"},"Example 4: Using ATAN with multiple arguments"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT ATAN(1.0, 2.0) AS atan FROM SingleItem;\n")),(0,r.yg)("p",null,"Error: Function expects 1 argument, but 2 were provided."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/bac2c42d.f5a5b87a.js b/docs/0.16.0/assets/js/bac2c42d.f5a5b87a.js new file mode 100644 index 00000000..756f1cd3 --- /dev/null +++ b/docs/0.16.0/assets/js/bac2c42d.f5a5b87a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[8604],{5680:(e,t,n)=>{n.d(t,{xA:()=>c,yg:()=>g});var a=n(6540);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?r(Object(n),!0).forEach((function(t){i(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):r(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,a,i=function(e,t){if(null==e)return{};var n,a,i={},r=Object.keys(e);for(a=0;a<r.length;a++)n=r[a],t.indexOf(n)>=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a<r.length;a++)n=r[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var l=a.createContext({}),u=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},c=function(e){var t=u(e.components);return a.createElement(l.Provider,{value:t},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,r=e.originalType,l=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),d=u(n),m=i,g=d["".concat(l,".").concat(m)]||d[m]||p[m]||r;return n?a.createElement(g,o(o({ref:t},c),{},{components:n})):a.createElement(g,o({ref:t},c))}));function g(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=n.length,o=new Array(r);o[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[d]="string"==typeof e?e:i,o[1]=s;for(var u=2;u<r;u++)o[u]=n[u];return a.createElement.apply(null,o)}return a.createElement.apply(null,n)}m.displayName="MDXCreateElement"},1829:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>o,default:()=>p,frontMatter:()=>r,metadata:()=>s,toc:()=>u});var a=n(8168),i=(n(6540),n(5680));const r={sidebar_position:3},o="Inserting Data",s={unversionedId:"ast-builder/statements/data-manipulation/inserting-data",id:"ast-builder/statements/data-manipulation/inserting-data",title:"Inserting Data",description:"In this section, we will discuss how to insert data into a table using GlueSQL.",source:"@site/docs/ast-builder/statements/data-manipulation/inserting-data.md",sourceDirName:"ast-builder/statements/data-manipulation",slug:"/ast-builder/statements/data-manipulation/inserting-data",permalink:"/docs/0.16.0/ast-builder/statements/data-manipulation/inserting-data",draft:!1,tags:[],version:"current",sidebarPosition:3,frontMatter:{sidebar_position:3},sidebar:"autoSidebar",previous:{title:"Data Sorting and Limiting",permalink:"/docs/0.16.0/ast-builder/statements/querying/data-sorting-and-limiting"},next:{title:"Updating Data",permalink:"/docs/0.16.0/ast-builder/statements/data-manipulation/updating-data"}},l={},u=[{value:"Basic Insert",id:"basic-insert",level:2},{value:"Insert with Specified Columns",id:"insert-with-specified-columns",level:2},{value:"Insert from Source",id:"insert-from-source",level:2}],c={toc:u},d="wrapper";function p(e){let{components:t,...n}=e;return(0,i.yg)(d,(0,a.A)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,i.yg)("h1",{id:"inserting-data"},"Inserting Data"),(0,i.yg)("p",null,"In this section, we will discuss how to insert data into a table using GlueSQL."),(0,i.yg)("h2",{id:"basic-insert"},"Basic Insert"),(0,i.yg)("p",null,"To insert data into a table, you can use the ",(0,i.yg)("inlineCode",{parentName:"p"},"insert")," method on a table object. You can then use the ",(0,i.yg)("inlineCode",{parentName:"p"},"values")," method to provide the values you want to insert."),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Foo")\n .insert()\n .values(vec!["1, \'Fruit\', 0.1", "2, \'Meat\', 0.8"])\n .execute(glue)\n .await;\nlet expected = Ok(Payload::Insert(2));\ntest(actual, expected);\n')),(0,i.yg)("p",null,"This code inserts two rows into the table ",(0,i.yg)("inlineCode",{parentName:"p"},"Foo"),". The first row has the values ",(0,i.yg)("inlineCode",{parentName:"p"},"1, 'Fruit', 0.1")," and the second row has the values ",(0,i.yg)("inlineCode",{parentName:"p"},"2, 'Meat', 0.8"),"."),(0,i.yg)("h2",{id:"insert-with-specified-columns"},"Insert with Specified Columns"),(0,i.yg)("p",null,"If you want to specify the columns to insert data into, you can use the ",(0,i.yg)("inlineCode",{parentName:"p"},"columns")," method followed by the ",(0,i.yg)("inlineCode",{parentName:"p"},"values")," method. The ",(0,i.yg)("inlineCode",{parentName:"p"},"values")," method should contain the data for the specified columns."),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Foo")\n .insert()\n .columns("id, name")\n .values(vec![vec![num(3), text("Drink")]])\n .execute(glue)\n .await;\nlet expected = Ok(Payload::Insert(1));\ntest(actual, expected);\n')),(0,i.yg)("p",null,"This code inserts a new row into the table ",(0,i.yg)("inlineCode",{parentName:"p"},"Foo")," with the specified columns ",(0,i.yg)("inlineCode",{parentName:"p"},"id")," and ",(0,i.yg)("inlineCode",{parentName:"p"},"name"),". The ",(0,i.yg)("inlineCode",{parentName:"p"},"rate")," column is not specified, so it will be set to its default value."),(0,i.yg)("h2",{id:"insert-from-source"},"Insert from Source"),(0,i.yg)("p",null,"You can also insert data into a table using a ",(0,i.yg)("inlineCode",{parentName:"p"},"SELECT")," statement as the source. To do this, use the ",(0,i.yg)("inlineCode",{parentName:"p"},"as_select")," method followed by the ",(0,i.yg)("inlineCode",{parentName:"p"},"execute")," method."),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Bar")\n .insert()\n .as_select(table("Foo").select().project("id, name"))\n .execute(glue)\n .await;\nlet expected = Ok(Payload::Insert(3));\ntest(actual, expected);\n')),(0,i.yg)("p",null,"This code inserts data into the table ",(0,i.yg)("inlineCode",{parentName:"p"},"Bar")," using the ",(0,i.yg)("inlineCode",{parentName:"p"},"SELECT")," statement on the table ",(0,i.yg)("inlineCode",{parentName:"p"},"Foo"),". The ",(0,i.yg)("inlineCode",{parentName:"p"},"project")," method is used to specify the columns ",(0,i.yg)("inlineCode",{parentName:"p"},"id")," and ",(0,i.yg)("inlineCode",{parentName:"p"},"name")," as the source data."))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/bb43b8ce.0fddfec9.js b/docs/0.16.0/assets/js/bb43b8ce.0fddfec9.js new file mode 100644 index 00000000..b5f1fc52 --- /dev/null +++ b/docs/0.16.0/assets/js/bb43b8ce.0fddfec9.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[5006],{5680:(e,t,n)=>{n.d(t,{xA:()=>u,yg:()=>g});var a=n(6540);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function l(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function i(e,t){if(null==e)return{};var n,a,r=function(e,t){if(null==e)return{};var n,a,r={},o=Object.keys(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=a.createContext({}),c=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},u=function(e){var t=c(e.components);return a.createElement(s.Provider,{value:t},e.children)},p="mdxType",y={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,s=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),p=c(n),d=r,g=p["".concat(s,".").concat(d)]||p[d]||y[d]||o;return n?a.createElement(g,l(l({ref:t},u),{},{components:n})):a.createElement(g,l({ref:t},u))}));function g(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,l=new Array(o);l[0]=d;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i[p]="string"==typeof e?e:r,l[1]=i;for(var c=2;c<o;c++)l[c]=n[c];return a.createElement.apply(null,l)}return a.createElement.apply(null,n)}d.displayName="MDXCreateElement"},5810:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>y,frontMatter:()=>o,metadata:()=>i,toc:()=>c});var a=n(8168),r=(n(6540),n(5680));const o={},l="CAST",i={unversionedId:"sql-syntax/functions/others/cast",id:"sql-syntax/functions/others/cast",title:"CAST",description:"The CAST function is used to convert a value from one data type to another. It is commonly used when you need to change the data type of a value or a column to perform a specific operation, such as arithmetic or string concatenation.",source:"@site/docs/sql-syntax/functions/others/cast.md",sourceDirName:"sql-syntax/functions/others",slug:"/sql-syntax/functions/others/cast",permalink:"/docs/0.16.0/sql-syntax/functions/others/cast",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"POINT",permalink:"/docs/0.16.0/sql-syntax/functions/geometry/point"},next:{title:"GENERATE_UUID",permalink:"/docs/0.16.0/sql-syntax/functions/others/generate-uuid"}},s={},c=[{value:"Syntax",id:"syntax",level:2},{value:"Examples",id:"examples",level:2},{value:"Converting a value to a different data type",id:"converting-a-value-to-a-different-data-type",level:3},{value:"Converting a column to a different data type",id:"converting-a-column-to-a-different-data-type",level:3},{value:"Handling NULL values",id:"handling-null-values",level:3},{value:"Converting a value to a DATE or TIME data type",id:"converting-a-value-to-a-date-or-time-data-type",level:3},{value:"Limitations and Errors",id:"limitations-and-errors",level:2}],u={toc:c},p="wrapper";function y(e){let{components:t,...n}=e;return(0,r.yg)(p,(0,a.A)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,r.yg)("h1",{id:"cast"},"CAST"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"CAST")," function is used to convert a value from one data type to another. It is commonly used when you need to change the data type of a value or a column to perform a specific operation, such as arithmetic or string concatenation."),(0,r.yg)("h2",{id:"syntax"},"Syntax"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"CAST(expression AS data_type)\n")),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"expression"),": The value or column you want to convert."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"data_type"),": The target data type to which you want to convert the expression.")),(0,r.yg)("h2",{id:"examples"},"Examples"),(0,r.yg)("h3",{id:"converting-a-value-to-a-different-data-type"},"Converting a value to a different data type"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT CAST('TRUE' AS BOOLEAN) AS cast;\n")),(0,r.yg)("p",null,"In this example, the ",(0,r.yg)("inlineCode",{parentName:"p"},"CAST")," function is used to convert the string ",(0,r.yg)("inlineCode",{parentName:"p"},"'TRUE'")," to a boolean value."),(0,r.yg)("h3",{id:"converting-a-column-to-a-different-data-type"},"Converting a column to a different data type"),(0,r.yg)("p",null,"Suppose you have a table called ",(0,r.yg)("inlineCode",{parentName:"p"},"employees")," with the following structure:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE employees (id INT, name TEXT, salary TEXT);\n")),(0,r.yg)("p",null,"To calculate the total salary of all employees, you can use the ",(0,r.yg)("inlineCode",{parentName:"p"},"CAST")," function to convert the ",(0,r.yg)("inlineCode",{parentName:"p"},"salary")," column to a ",(0,r.yg)("inlineCode",{parentName:"p"},"DECIMAL")," data type:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT SUM(CAST(salary AS DECIMAL)) AS total_salary FROM employees;\n")),(0,r.yg)("h3",{id:"handling-null-values"},"Handling NULL values"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"CAST")," function can handle NULL values as well. If the expression is NULL, the result will be NULL:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT CAST(NULL AS INTEGER) AS cast;\n")),(0,r.yg)("p",null,"This query will return a NULL value."),(0,r.yg)("h3",{id:"converting-a-value-to-a-date-or-time-data-type"},"Converting a value to a DATE or TIME data type"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"CAST")," function can also be used to convert strings to DATE or TIME data types:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT CAST('2023-05-04' AS DATE) AS cast_date;\nSELECT CAST('14:30:00' AS TIME) AS cast_time;\n")),(0,r.yg)("p",null,"These queries will return a date and time value, respectively."),(0,r.yg)("h2",{id:"limitations-and-errors"},"Limitations and Errors"),(0,r.yg)("p",null,"Some conversions may be impossible or result in an error. For example, trying to convert a non-numeric string to an integer will result in an error:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT CAST('foo' AS INTEGER) AS cast;\n")),(0,r.yg)("p",null,"This query will produce an error because the string ",(0,r.yg)("inlineCode",{parentName:"p"},"'foo'")," cannot be converted to an integer."))}y.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/bfb64759.8ed694c2.js b/docs/0.16.0/assets/js/bfb64759.8ed694c2.js new file mode 100644 index 00000000..5e22cf53 --- /dev/null +++ b/docs/0.16.0/assets/js/bfb64759.8ed694c2.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[7794],{5680:(e,n,t)=>{t.d(n,{xA:()=>s,yg:()=>y});var a=t(6540);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function i(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function u(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?i(Object(t),!0).forEach((function(n){r(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):i(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function l(e,n){if(null==e)return{};var t,a,r=function(e,n){if(null==e)return{};var t,a,r={},i=Object.keys(e);for(a=0;a<i.length;a++)t=i[a],n.indexOf(t)>=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a<i.length;a++)t=i[a],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var o=a.createContext({}),d=function(e){var n=a.useContext(o),t=n;return e&&(t="function"==typeof e?e(n):u(u({},n),e)),t},s=function(e){var n=d(e.components);return a.createElement(o.Provider,{value:n},e.children)},p="mdxType",c={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},g=a.forwardRef((function(e,n){var t=e.components,r=e.mdxType,i=e.originalType,o=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),p=d(t),g=r,y=p["".concat(o,".").concat(g)]||p[g]||c[g]||i;return t?a.createElement(y,u(u({ref:n},s),{},{components:t})):a.createElement(y,u({ref:n},s))}));function y(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var i=t.length,u=new Array(i);u[0]=g;var l={};for(var o in n)hasOwnProperty.call(n,o)&&(l[o]=n[o]);l.originalType=e,l[p]="string"==typeof e?e:r,u[1]=l;for(var d=2;d<i;d++)u[d]=t[d];return a.createElement.apply(null,u)}return a.createElement.apply(null,t)}g.displayName="MDXCreateElement"},2029:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>o,contentTitle:()=>u,default:()=>c,frontMatter:()=>i,metadata:()=>l,toc:()=>d});var a=t(8168),r=(t(6540),t(5680));const i={},u="UUID",l={unversionedId:"sql-syntax/data-types/uuid",id:"sql-syntax/data-types/uuid",title:"UUID",description:"The UUID data type in SQL is used to store universally unique identifiers (UUIDs). These identifiers can be compared, filtered, and sorted using standard SQL operations.",source:"@site/docs/sql-syntax/data-types/uuid.md",sourceDirName:"sql-syntax/data-types",slug:"/sql-syntax/data-types/uuid",permalink:"/docs/0.16.0/sql-syntax/data-types/uuid",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"INET",permalink:"/docs/0.16.0/sql-syntax/data-types/inet"},next:{title:"ASCII",permalink:"/docs/0.16.0/sql-syntax/functions/text/ascii"}},o={},d=[{value:"Creating a table with a UUID column",id:"creating-a-table-with-a-uuid-column",level:2},{value:"Inserting data into the UUID column",id:"inserting-data-into-the-uuid-column",level:2},{value:"Generating a random UUID",id:"generating-a-random-uuid",level:2},{value:"Querying data from the UUID column",id:"querying-data-from-the-uuid-column",level:2},{value:"Filtering and manipulating data using the UUID column",id:"filtering-and-manipulating-data-using-the-uuid-column",level:2}],s={toc:d},p="wrapper";function c(e){let{components:n,...t}=e;return(0,r.yg)(p,(0,a.A)({},s,t,{components:n,mdxType:"MDXLayout"}),(0,r.yg)("h1",{id:"uuid"},"UUID"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"UUID")," data type in SQL is used to store universally unique identifiers (UUIDs). These identifiers can be compared, filtered, and sorted using standard SQL operations."),(0,r.yg)("p",null,"Here's an example of how to create a table, insert data, and query data using the ",(0,r.yg)("inlineCode",{parentName:"p"},"UUID")," data type:"),(0,r.yg)("h2",{id:"creating-a-table-with-a-uuid-column"},"Creating a table with a UUID column"),(0,r.yg)("p",null,"To create a table with a UUID column, use the following SQL syntax:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE UUID (uuid_field UUID);\n")),(0,r.yg)("h2",{id:"inserting-data-into-the-uuid-column"},"Inserting data into the UUID column"),(0,r.yg)("p",null,"To insert data into the UUID column, provide the UUIDs as strings or in the format ",(0,r.yg)("inlineCode",{parentName:"p"},"X'<hexadecimal_value>'"),". You can also use the ",(0,r.yg)("inlineCode",{parentName:"p"},"urn:uuid:")," prefix. Note that providing a UUID as a plain number is not supported and will result in an error."),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO UUID VALUES\n (X'936DA01F9ABD4d9d80C702AF85C822A8'),\n ('550e8400-e29b-41d4-a716-446655440000'),\n ('urn:uuid:F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4');\n")),(0,r.yg)("h2",{id:"generating-a-random-uuid"},"Generating a random UUID"),(0,r.yg)("p",null,"To generate a random UUID (version 4), use the ",(0,r.yg)("inlineCode",{parentName:"p"},"GENERATE_UUID")," function:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO UUID (uuid_field) VALUES (GENERATE_UUID());\n")),(0,r.yg)("h2",{id:"querying-data-from-the-uuid-column"},"Querying data from the UUID column"),(0,r.yg)("p",null,"To query data from the UUID column, use standard SQL syntax:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT uuid_field FROM UUID;\n")),(0,r.yg)("p",null,"This query will return the following result:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre"},"uuid_field\n------------------------------------\n936DA01F-9ABD-4D9D-80C7-02AF85C822A8\n550E8400-E29B-41D4-A716-446655440000\nF9168C5E-CEB2-4FAA-B6BF-329BF39FA1E4\n")),(0,r.yg)("h2",{id:"filtering-and-manipulating-data-using-the-uuid-column"},"Filtering and manipulating data using the UUID column"),(0,r.yg)("p",null,"You can filter, update, and delete data using the UUID column with standard SQL operations:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"-- Filtering\nSELECT uuid_field FROM UUID WHERE uuid_field = '550e8400-e29b-41d4-a716-446655440000';\n\n-- Updating\nUPDATE UUID SET uuid_field = 'urn:uuid:F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4' WHERE uuid_field = '550e8400-e29b-41d4-a716-446655440000';\n\n-- Deleting\nDELETE FROM UUID WHERE uuid_field = '550e8400-e29b-41d4-a716-446655440000';\n")))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/c251e734.3fd3d58f.js b/docs/0.16.0/assets/js/c251e734.3fd3d58f.js new file mode 100644 index 00000000..7590f298 --- /dev/null +++ b/docs/0.16.0/assets/js/c251e734.3fd3d58f.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[7179],{5680:(e,t,r)=>{r.d(t,{xA:()=>p,yg:()=>m});var n=r(6540);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function a(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?i(Object(r),!0).forEach((function(t){o(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):i(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function s(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=n.createContext({}),u=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},p=function(e){var t=u(e.components);return n.createElement(l.Provider,{value:t},e.children)},c="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},g=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,i=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),c=u(r),g=o,m=c["".concat(l,".").concat(g)]||c[g]||d[g]||i;return r?n.createElement(m,a(a({ref:t},p),{},{components:r})):n.createElement(m,a({ref:t},p))}));function m(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=r.length,a=new Array(i);a[0]=g;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[c]="string"==typeof e?e:o,a[1]=s;for(var u=2;u<i;u++)a[u]=r[u];return n.createElement.apply(null,a)}return n.createElement.apply(null,r)}g.displayName="MDXCreateElement"},5926:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>a,default:()=>d,frontMatter:()=>i,metadata:()=>s,toc:()=>u});var n=r(8168),o=(r(6540),r(5680));const i={sidebar_position:1},a="Introduction",s={unversionedId:"storages/developing-custom-storages/intro",id:"storages/developing-custom-storages/intro",title:"Introduction",description:"With GlueSQL, you can adapt SQL and the AST Builder to a wide variety of environments. This includes file systems, key-value databases, complex NoSQL databases, and even remote APIs. As long as a system supports reading, it can support SELECT queries. If it supports both reading and writing, it can support most SQL operations, including UPDATE and DELETE.",source:"@site/docs/storages/developing-custom-storages/intro.md",sourceDirName:"storages/developing-custom-storages",slug:"/storages/developing-custom-storages/intro",permalink:"/docs/0.16.0/storages/developing-custom-storages/intro",draft:!1,tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"autoSidebar",previous:{title:"WebStorage (local & session)",permalink:"/docs/0.16.0/storages/supported-storages/web-storage"},next:{title:"Store",permalink:"/docs/0.16.0/storages/developing-custom-storages/store-traits/store"}},l={},u=[{value:"Understanding Store Traits",id:"understanding-store-traits",level:2},{value:"Using the Test Suite",id:"using-the-test-suite",level:2}],p={toc:u},c="wrapper";function d(e){let{components:t,...r}=e;return(0,o.yg)(c,(0,n.A)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,o.yg)("h1",{id:"introduction"},"Introduction"),(0,o.yg)("p",null,"With GlueSQL, you can adapt SQL and the AST Builder to a wide variety of environments. This includes file systems, key-value databases, complex NoSQL databases, and even remote APIs. As long as a system supports reading, it can support SELECT queries. If it supports both reading and writing, it can support most SQL operations, including UPDATE and DELETE."),(0,o.yg)("p",null,"To implement GlueSQL, you only need to know two things:"),(0,o.yg)("ol",null,(0,o.yg)("li",{parentName:"ol"},"Understanding Store traits"),(0,o.yg)("li",{parentName:"ol"},"Using the Test Suite")),(0,o.yg)("p",null,"These topics are covered in more detail in their respective pages, but here we will provide a brief overview."),(0,o.yg)("h2",{id:"understanding-store-traits"},"Understanding Store Traits"),(0,o.yg)("p",null,"GlueSQL is available in both Rust and JavaScript environments, with plans to expand its support to other languages. Since the GlueSQL project itself is written in Rust, using Rust is essential for developing custom storages. To create a custom storage, you need to implement the Store traits provided by GlueSQL. There are currently 9 traits:"),(0,o.yg)("ul",null,(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("inlineCode",{parentName:"li"},"Store")," - A trait for read operations to support SELECT queries."),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("inlineCode",{parentName:"li"},"StoreMut")," - A trait for modifying data, such as INSERT, UPDATE, and DELETE."),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("inlineCode",{parentName:"li"},"AlterTable")," - A trait for supporting schema changes."),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("inlineCode",{parentName:"li"},"Transaction")," - A trait for supporting transactions."),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("inlineCode",{parentName:"li"},"CustomFunction")," - A trait for supporting user-level custom functions."),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("inlineCode",{parentName:"li"},"CustomFunctionMut")," - A trait for creating or deleting user-level custom functions."),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("inlineCode",{parentName:"li"},"Index")," - A trait for supporting non-clustered indexes. This trait allows you to process pre-registered indexes."),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("inlineCode",{parentName:"li"},"IndexMut")," - A trait for creating or deleting non-clustered indexes."),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("inlineCode",{parentName:"li"},"Metadata")," - A trait for querying metadata.")),(0,o.yg)("p",null,"To develop a custom storage, you can implement these 9 traits. Although this may seem like a lot of work, don't worry. All traits except for ",(0,o.yg)("inlineCode",{parentName:"p"},"Store")," and ",(0,o.yg)("inlineCode",{parentName:"p"},"StoreMut")," are optional. In other words, you don't have to implement them. If you don't want to support the ",(0,o.yg)("inlineCode",{parentName:"p"},"AlterTable")," trait, simply don't implement it. It's that simple."),(0,o.yg)("p",null,"Furthermore, if you only want to support SELECT queries, you don't need to implement ",(0,o.yg)("inlineCode",{parentName:"p"},"StoreMut"),". By implementing only the ",(0,o.yg)("inlineCode",{parentName:"p"},"Store")," trait, you can create a custom storage that supports SQL SELECT queries."),(0,o.yg)("h2",{id:"using-the-test-suite"},"Using the Test Suite"),(0,o.yg)("p",null,"The minimum requirement for developing a custom storage is implementing the Store traits. However, you may want to verify that your implementation is correct. That's where the Test Suite comes in."),(0,o.yg)("p",null,"GlueSQL provides a test case library to make it easy to validate custom storage development. Developers can implement the desired Store traits and use the Test Suite to verify that their implementation is correct. The line coverage of GlueSQL's core project is almost 99%, which means that passing the Test Suite alone can complete most of the feature verification. All you need to do is ensure your custom storage passes the Test Suite and write additional tests for any specialized features specific to your storage."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/c2e5ab4f.ab7e6240.js b/docs/0.16.0/assets/js/c2e5ab4f.ab7e6240.js new file mode 100644 index 00000000..c264b8f2 --- /dev/null +++ b/docs/0.16.0/assets/js/c2e5ab4f.ab7e6240.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[2245],{5680:(e,t,n)=>{n.d(t,{xA:()=>m,yg:()=>d});var r=n(6540);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},i=Object.keys(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=r.createContext({}),c=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},m=function(e){var t=c(e.components);return r.createElement(l.Provider,{value:t},e.children)},p="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},g=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,l=e.parentName,m=s(e,["components","mdxType","originalType","parentName"]),p=c(n),g=a,d=p["".concat(l,".").concat(g)]||p[g]||u[g]||i;return n?r.createElement(d,o(o({ref:t},m),{},{components:n})):r.createElement(d,o({ref:t},m))}));function d(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,o=new Array(i);o[0]=g;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[p]="string"==typeof e?e:a,o[1]=s;for(var c=2;c<i;c++)o[c]=n[c];return r.createElement.apply(null,o)}return r.createElement.apply(null,n)}g.displayName="MDXCreateElement"},8535:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>o,default:()=>u,frontMatter:()=>i,metadata:()=>s,toc:()=>c});var r=n(8168),a=(n(6540),n(5680));const i={},o="TO_TIMESTAMP",s={unversionedId:"sql-syntax/functions/datetime/to-timestamp",id:"sql-syntax/functions/datetime/to-timestamp",title:"TO_TIMESTAMP",description:"The TO_TIMESTAMP function in SQL is used to convert a string into a TIMESTAMP. This function takes two arguments, the string to be converted and a format string that specifies the format of the input string.",source:"@site/docs/sql-syntax/functions/datetime/to-timestamp.md",sourceDirName:"sql-syntax/functions/datetime",slug:"/sql-syntax/functions/datetime/to-timestamp",permalink:"/docs/0.16.0/sql-syntax/functions/datetime/to-timestamp",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"TO_TIME",permalink:"/docs/0.16.0/sql-syntax/functions/datetime/to-time"},next:{title:"APPEND",permalink:"/docs/0.16.0/sql-syntax/functions/list-map/append"}},l={},c=[{value:"Syntax",id:"syntax",level:2},{value:"Examples",id:"examples",level:2},{value:"Converting a string to a TIMESTAMP",id:"converting-a-string-to-a-timestamp",level:3},{value:"Selecting a converted string to a TIMESTAMP",id:"selecting-a-converted-string-to-a-timestamp",level:3},{value:"Error Handling",id:"error-handling",level:2}],m={toc:c},p="wrapper";function u(e){let{components:t,...n}=e;return(0,a.yg)(p,(0,r.A)({},m,n,{components:t,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"to_timestamp"},"TO_TIMESTAMP"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"TO_TIMESTAMP")," function in SQL is used to convert a string into a TIMESTAMP. This function takes two arguments, the string to be converted and a format string that specifies the format of the input string."),(0,a.yg)("h2",{id:"syntax"},"Syntax"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"TO_TIMESTAMP(string, format)\n")),(0,a.yg)("h2",{id:"examples"},"Examples"),(0,a.yg)("h3",{id:"converting-a-string-to-a-timestamp"},"Converting a string to a TIMESTAMP"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"VALUES(TO_TIMESTAMP('2015-09-05 23:56:04', '%Y-%m-%d %H:%M:%S'));\n")),(0,a.yg)("p",null,"In this example, the string '2015-09-05 23:56:04' is converted into a TIMESTAMP using the format '%Y-%m-%d %H:%M:%S', where %Y is the four-digit year, %m is the two-digit month, %d is the two-digit day, %H is the two-digit hour, %M is the two-digit minute, and %S is the two-digit second."),(0,a.yg)("h3",{id:"selecting-a-converted-string-to-a-timestamp"},"Selecting a converted string to a TIMESTAMP"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT TO_TIMESTAMP('2015-09-05 23:56:04', '%Y-%m-%d %H:%M:%S') AS timestamp;\n")),(0,a.yg)("p",null,"In this example, the string '2015-09-05 23:56:04' is converted into a TIMESTAMP using the format '%Y-%m-%d %H:%M:%S' and selected as 'timestamp'."),(0,a.yg)("h2",{id:"error-handling"},"Error Handling"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"TO_TIMESTAMP")," function requires a string value as its first argument. If a non-string value is provided, it will return an error."),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT TO_TIMESTAMP(TIMESTAMP '2015-09-05 23:56:04','%Y-%m-%d') AS timestamp;\n")),(0,a.yg)("p",null,"In this case, the TIMESTAMP '2015-09-05 23:56:04' is not a string and will cause an error."),(0,a.yg)("p",null,"Additionally, if the format string does not match the format of the input string, an error will also be returned. For example:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT TO_TIMESTAMP('2015-09-05 23:56:04', '%Y-%m-%d %H:%M') AS timestamp;\n")),(0,a.yg)("p",null,"In this case, the format string '%Y-%m-%d %H:%M' does not match the input string '2015-09-05 23:56:04', so an error will be returned."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/c30ee527.527297e3.js b/docs/0.16.0/assets/js/c30ee527.527297e3.js new file mode 100644 index 00000000..06420a60 --- /dev/null +++ b/docs/0.16.0/assets/js/c30ee527.527297e3.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[6204],{5680:(e,t,n)=>{n.d(t,{xA:()=>c,yg:()=>d});var a=n(6540);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function s(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?s(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):s(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,a,r=function(e,t){if(null==e)return{};var n,a,r={},s=Object.keys(e);for(a=0;a<s.length;a++)n=s[a],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(a=0;a<s.length;a++)n=s[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var i=a.createContext({}),p=function(e){var t=a.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},c=function(e){var t=p(e.components);return a.createElement(i.Provider,{value:t},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},y=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,s=e.originalType,i=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),u=p(n),y=r,d=u["".concat(i,".").concat(y)]||u[y]||m[y]||s;return n?a.createElement(d,o(o({ref:t},c),{},{components:n})):a.createElement(d,o({ref:t},c))}));function d(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var s=n.length,o=new Array(s);o[0]=y;var l={};for(var i in t)hasOwnProperty.call(t,i)&&(l[i]=t[i]);l.originalType=e,l[u]="string"==typeof e?e:r,o[1]=l;for(var p=2;p<s;p++)o[p]=n[p];return a.createElement.apply(null,o)}return a.createElement.apply(null,n)}y.displayName="MDXCreateElement"},351:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>i,contentTitle:()=>o,default:()=>m,frontMatter:()=>s,metadata:()=>l,toc:()=>p});var a=n(8168),r=(n(6540),n(5680));const s={sidebar_position:1},o="SHOW TABLES",l={unversionedId:"sql-syntax/statements/metadata/show-tables",id:"sql-syntax/statements/metadata/show-tables",title:"SHOW TABLES",description:"The SHOW TABLES statement in GlueSQL is used to display a list of tables available in the database. This statement is useful when you want to inspect the current structure of your database or when you want to manage multiple tables.",source:"@site/docs/sql-syntax/statements/metadata/show-tables.md",sourceDirName:"sql-syntax/statements/metadata",slug:"/sql-syntax/statements/metadata/show-tables",permalink:"/docs/0.16.0/sql-syntax/statements/metadata/show-tables",draft:!1,tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"autoSidebar",previous:{title:"Transaction",permalink:"/docs/0.16.0/sql-syntax/statements/transaction"},next:{title:"Data Dictionary",permalink:"/docs/0.16.0/sql-syntax/statements/metadata/data-dictionary"}},i={},p=[{value:"Syntax",id:"syntax",level:2},{value:"Example",id:"example",level:2}],c={toc:p},u="wrapper";function m(e){let{components:t,...n}=e;return(0,r.yg)(u,(0,a.A)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,r.yg)("h1",{id:"show-tables"},"SHOW TABLES"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"SHOW TABLES")," statement in GlueSQL is used to display a list of tables available in the database. This statement is useful when you want to inspect the current structure of your database or when you want to manage multiple tables."),(0,r.yg)("h2",{id:"syntax"},"Syntax"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SHOW TABLES;\n")),(0,r.yg)("h2",{id:"example"},"Example"),(0,r.yg)("p",null,"Consider the following example where we create a few tables and then use the ",(0,r.yg)("inlineCode",{parentName:"p"},"SHOW TABLES")," statement to list them:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE Foo (id INTEGER, name TEXT NULL, type TEXT NULL);\nCREATE TABLE Zoo (id INTEGER);\nCREATE TABLE Bar (id INTEGER, name TEXT NULL);\n\nSHOW TABLES;\n")),(0,r.yg)("p",null,"The output of the ",(0,r.yg)("inlineCode",{parentName:"p"},"SHOW TABLES")," statement will be:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre"},"Bar\nFoo\nZoo\n")),(0,r.yg)("p",null,"The tables are listed in alphabetical order."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/c34cc4c9.56ce985b.js b/docs/0.16.0/assets/js/c34cc4c9.56ce985b.js new file mode 100644 index 00000000..ee44e8fd --- /dev/null +++ b/docs/0.16.0/assets/js/c34cc4c9.56ce985b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[5427],{5484:s=>{s.exports=JSON.parse('{"label":"ChatGPT","permalink":"/docs/0.16.0/blog/tags/chat-gpt","allTagsPath":"/docs/0.16.0/blog/tags","count":1}')}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/c377a04b.809da12b.js b/docs/0.16.0/assets/js/c377a04b.809da12b.js new file mode 100644 index 00000000..a4ee0443 --- /dev/null +++ b/docs/0.16.0/assets/js/c377a04b.809da12b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[5742],{5680:(e,t,a)=>{a.d(t,{xA:()=>d,yg:()=>m});var o=a(6540);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function s(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,o)}return a}function n(e){for(var t=1;t<arguments.length;t++){var a=null!=arguments[t]?arguments[t]:{};t%2?s(Object(a),!0).forEach((function(t){r(e,t,a[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(a)):s(Object(a)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(a,t))}))}return e}function i(e,t){if(null==e)return{};var a,o,r=function(e,t){if(null==e)return{};var a,o,r={},s=Object.keys(e);for(o=0;o<s.length;o++)a=s[o],t.indexOf(a)>=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(o=0;o<s.length;o++)a=s[o],t.indexOf(a)>=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var l=o.createContext({}),u=function(e){var t=o.useContext(l),a=t;return e&&(a="function"==typeof e?e(t):n(n({},t),e)),a},d=function(e){var t=u(e.components);return o.createElement(l.Provider,{value:t},e.children)},g="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},c=o.forwardRef((function(e,t){var a=e.components,r=e.mdxType,s=e.originalType,l=e.parentName,d=i(e,["components","mdxType","originalType","parentName"]),g=u(a),c=r,m=g["".concat(l,".").concat(c)]||g[c]||p[c]||s;return a?o.createElement(m,n(n({ref:t},d),{},{components:a})):o.createElement(m,n({ref:t},d))}));function m(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var s=a.length,n=new Array(s);n[0]=c;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i[g]="string"==typeof e?e:r,n[1]=i;for(var u=2;u<s;u++)n[u]=a[u];return o.createElement.apply(null,n)}return o.createElement.apply(null,a)}c.displayName="MDXCreateElement"},1866:(e,t,a)=>{a.r(t),a.d(t,{assets:()=>l,contentTitle:()=>n,default:()=>p,frontMatter:()=>s,metadata:()=>i,toc:()=>u});var o=a(8168),r=(a(6540),a(5680));const s={sidebar_position:1},n="Introduction",i={unversionedId:"index",id:"index",title:"Introduction",description:"crates.io",source:"@site/docs/index.md",sourceDirName:".",slug:"/",permalink:"/docs/0.16.0/",draft:!1,tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"autoSidebar",next:{title:"Rust",permalink:"/docs/0.16.0/getting-started/rust"}},l={},u=[{value:"Multi-Model Database Engine as a Library",id:"multi-model-database-engine-as-a-library",level:2},{value:"Supporting SQL and AST Builder",id:"supporting-sql-and-ast-builder",level:2},{value:"SQL Example",id:"sql-example",level:3},{value:"AST Builder Example",id:"ast-builder-example",level:3},{value:"Supporting Structured and Unstructured Data with Schema Flexibility",id:"supporting-structured-and-unstructured-data-with-schema-flexibility",level:2},{value:"Schemaless SQL Example",id:"schemaless-sql-example",level:3},{value:"Supported Reference Storages",id:"supported-reference-storages",level:2},{value:"Memory Storage",id:"memory-storage",level:3},{value:"Shared Memory Storage",id:"shared-memory-storage",level:3},{value:"Sled Storage",id:"sled-storage",level:3},{value:"JSON Storage",id:"json-storage",level:3},{value:"CSV Storage",id:"csv-storage",level:3},{value:"Parquet Storage",id:"parquet-storage",level:3},{value:"File Storage",id:"file-storage",level:3},{value:"Git Storage",id:"git-storage",level:3},{value:"Mongo Storage",id:"mongo-storage",level:3},{value:"Web Storage",id:"web-storage",level:3},{value:"IndexedDB Storage",id:"indexeddb-storage",level:3},{value:"Composite Storage",id:"composite-storage",level:3},{value:"Adapting GlueSQL to Your Environment: Creating Custom Storage",id:"adapting-gluesql-to-your-environment-creating-custom-storage",level:2},{value:"GlueSQL Custom Storage: Let Us Handle It for You",id:"gluesql-custom-storage-let-us-handle-it-for-you",level:2},{value:"Contribution",id:"contribution",level:2},{value:"License",id:"license",level:2}],d={toc:u},g="wrapper";function p(e){let{components:t,...a}=e;return(0,r.yg)(g,(0,o.A)({},d,a,{components:t,mdxType:"MDXLayout"}),(0,r.yg)("h1",{id:"introduction"},"Introduction"),(0,r.yg)("p",null,(0,r.yg)("a",{parentName:"p",href:"https://crates.io/crates/gluesql"},(0,r.yg)("img",{parentName:"a",src:"https://img.shields.io/crates/v/gluesql.svg",alt:"crates.io"})),"\n",(0,r.yg)("a",{parentName:"p",href:"https://www.npmjs.com/package/gluesql"},(0,r.yg)("img",{parentName:"a",src:"https://img.shields.io/npm/v/gluesql?color=red",alt:"npm"})),"\n",(0,r.yg)("a",{parentName:"p",href:"https://github.com/gluesql/gluesql/blob/main/LICENSE"},(0,r.yg)("img",{parentName:"a",src:"https://img.shields.io/crates/l/gluesql.svg",alt:"LICENSE"})),"\n",(0,r.yg)("img",{parentName:"p",src:"https://github.com/gluesql/gluesql/workflows/Rust/badge.svg",alt:"Rust"}),"\n",(0,r.yg)("a",{parentName:"p",href:"https://docs.rs/gluesql"},(0,r.yg)("img",{parentName:"a",src:"https://docs.rs/gluesql/badge.svg",alt:"docs.rs"})),"\n",(0,r.yg)("a",{parentName:"p",href:"https://discord.gg/C6TDEgzDzY"},(0,r.yg)("img",{parentName:"a",src:"https://img.shields.io/discord/780298017940176946?logo=discord&logoColor=white",alt:"Chat"})),"\n",(0,r.yg)("a",{parentName:"p",href:"https://coveralls.io/github/gluesql/gluesql?branch=main"},(0,r.yg)("img",{parentName:"a",src:"https://coveralls.io/repos/github/gluesql/gluesql/badge.svg?branch=main",alt:"Coverage Status"}))),(0,r.yg)("h2",{id:"multi-model-database-engine-as-a-library"},"Multi-Model Database Engine as a Library"),(0,r.yg)("p",null,"GlueSQL is a Rust library for SQL databases that includes a parser (",(0,r.yg)("a",{parentName:"p",href:"https://github.com/sqlparser-rs/sqlparser-rs"},"sqlparser-rs"),"), an execution layer, and a variety of storage options, both persistent and non-persistent, all in one package. It is a versatile tool for developers, supporting both SQL and its own query builder (AST Builder). GlueSQL can handle structured and unstructured data, making it suitable for a wide range of use cases. It is portable and can be used with various storage types, including log files and read-write capable storage. GlueSQL is designed to be extensible and supports custom planners, making it a powerful tool for developers who need SQL support for their databases or services. GlueSQL is also flexible, as it can be used in Rust and JavaScript environments, and its language support is constantly expanding to include more programming languages."),(0,r.yg)("p",null,'"We offer a service where the GlueSQL team can implement and maintain your custom storage, especially beneficial for NoSQL databases with their own query planner and execution layer. We welcome any services wishing to support SQL and GlueSQL query interfaces. For more details, please refer to ',(0,r.yg)("a",{parentName:"p",href:"#gluesql-custom-storage-let-us-handle-it-for-you"},(0,r.yg)("strong",{parentName:"a"},"here")),'."'),(0,r.yg)("p",null,"If you're interested in learning more about GlueSQL, we recommend the following blog articles for a deeper dive into its capabilities and benefits:"),(0,r.yg)("ol",null,(0,r.yg)("li",{parentName:"ol"},(0,r.yg)("a",{parentName:"li",href:"https://gluesql.org/blog/breaking-the-boundary-between-sql-and-nosql"},"Breaking the Boundary between SQL and NoSQL Database")),(0,r.yg)("li",{parentName:"ol"},(0,r.yg)("a",{parentName:"li",href:"https://gluesql.org/blog/revolutionizing-databases-by-unifying-query-interfaces"},"Revolutionizing Databases by Unifying Query Interfaces")),(0,r.yg)("li",{parentName:"ol"},(0,r.yg)("a",{parentName:"li",href:"https://gluesql.org/blog/test-driven-documentation"},"Test-Driven Documentation - Automating User Manual Creation"))),(0,r.yg)("h2",{id:"supporting-sql-and-ast-builder"},"Supporting SQL and AST Builder"),(0,r.yg)("p",null,"GlueSQL supports both SQL and its own query builder (AST Builder). Unlike other ORMs, GlueSQL's AST Builder allows developers to build queries directly with GlueSQL's AST, enabling the use of all of GlueSQL's features. This is why we named it AST Builder instead of Query Builder."),(0,r.yg)("h3",{id:"sql-example"},"SQL Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT id, name FROM Foo WHERE name = 'Lemon' AND price > 100\n")),(0,r.yg)("h3",{id:"ast-builder-example"},"AST Builder Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-rust"},'table("Foo")\n .select()\n // Filter by name using a SQL string\n .filter("name = \'Lemon\'")\n // Filter by price using AST Builder methods\n .filter(col("price").gt(100))\n .project("id, name")\n .execute(glue)\n .await;\n')),(0,r.yg)("h2",{id:"supporting-structured-and-unstructured-data-with-schema-flexibility"},"Supporting Structured and Unstructured Data with Schema Flexibility"),(0,r.yg)("p",null,"GlueSQL supports both structured and unstructured (schemaless) data. While SQL databases typically assume that schemas are defined and used, GlueSQL does not make this assumption. It supports completely unstructured data, similar to a NoSQL document database, as well as semi-structured types such as MAP and LIST. This makes GlueSQL suitable for a wide range of use cases, including those that require handling of unstructured data. Additionally, it is possible to join tables with schemas and schemaless tables together and execute queries."),(0,r.yg)("h3",{id:"schemaless-sql-example"},"Schemaless SQL Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},'CREATE TABLE Names (id INTEGER, name TEXT);\nINSERT INTO Names VALUES (1, \'glue\'), (2, \'sql\');\n\nCREATE TABLE Logs;\nINSERT INTO Logs VALUES\n (\'{ "id": 1, "value": 30 }\'),\n (\'{ "id": 2, "rate": 3.0, "list": [1, 2, 3] }\'),\n (\'{ "id": 3, "rate": 5.0, "value": 100 }\');\n\nSELECT * FROM Names JOIN Logs ON Names.id = Logs.id;\n/*\n| id | list | name | rate | value |\n|----|---------|------|------|-------|\n| 1 | | glue | | 30 |\n| 2 |[1, 2, 3]| sql | 3 | |\n*/\n')),(0,r.yg)("h2",{id:"supported-reference-storages"},"Supported Reference Storages"),(0,r.yg)("p",null,"GlueSQL provides a variety of reference storages out of the box, including simple in-memory storage, key-value databases, log file-based storage like JSON & JSONL, and even Web Storage and IndexedDB supported by web browsers. These reference storages are readily available for use and can be easily adapted to a variety of storage systems. Additionally, GlueSQL is constantly expanding its list of supported storages, making it a versatile tool for developers."),(0,r.yg)("h3",{id:"memory-storage"},"Memory Storage"),(0,r.yg)("p",null,"Memory Storage is a foundational storage option designed for in-memory, non-persistent data. It is a simple yet robust storage option that can be used in production environments."),(0,r.yg)("h3",{id:"shared-memory-storage"},"Shared Memory Storage"),(0,r.yg)("p",null,"Shared Memory Storage is a storage option designed to provide more comfortable usage of Memory Storage in concurrent environments. It wraps the Memory Storage with a read-write lock and an atomic reference count, allowing you to clone the storage instance and use it effortlessly across multiple threads. All storage instances will refer to the same data, making it a convenient option for concurrent environments."),(0,r.yg)("h3",{id:"sled-storage"},"Sled Storage"),(0,r.yg)("p",null,"Sled Storage is a persistent data storage option for GlueSQL that is built on the Sled key-value embedded database in Rust. It is the only storage option currently supported by GlueSQL that implements all Store traits, from non-clustered indexes to transactions. Sled Storage is an excellent choice for handling and storing data in a Rust environment. To use Sled Storage, you can create a SledStorage instance using a path."),(0,r.yg)("h3",{id:"json-storage"},"JSON Storage"),(0,r.yg)("p",null,"With GlueSQL, you can use JSONL or JSON files as a database that supports SQL and AST Builder, making it a powerful option for developers who need to work with JSON data. JSON Storage is a storage system that uses two types of files: a schema file (optional) and a data file. The schema file is written in Standard SQL and stores the structure of the table, while the data file contains the actual data and supports two file formats: ",(0,r.yg)("inlineCode",{parentName:"p"},"*.json")," and ",(0,r.yg)("inlineCode",{parentName:"p"},"*.jsonl"),". JSON Storage supports all DML features, but is particularly specialized for SELECT and INSERT."),(0,r.yg)("h3",{id:"csv-storage"},"CSV Storage"),(0,r.yg)("p",null,"CSV Storage in GlueSQL allows you to work with CSV files as if they were SQL databases. This feature is perfect for developers who want to use the simplicity of CSV files while taking advantage of SQL's capabilities."),(0,r.yg)("h3",{id:"parquet-storage"},"Parquet Storage"),(0,r.yg)("p",null,"Parquet Storage in GlueSQL allows you to treat Parquet files as SQL databases, enabling SQL operations like SELECT, INSERT, and UPDATE directly on Parquet data. It offers a convenient way to work with the efficiency and structure of Parquet files while utilizing the full power of SQL."),(0,r.yg)("h3",{id:"file-storage"},"File Storage"),(0,r.yg)("p",null,"File Storage is a custom storage implementation that utilizes the filesystem.\nFor each table name, the schema information is saved in a .sql format using a CREATE TABLE query.\nThe data is stored by creating a directory with the same name as the table and serializing the data using RON format in the subdirectory."),(0,r.yg)("h3",{id:"git-storage"},"Git Storage"),(0,r.yg)("p",null,"Git Storage is a custom storage option in GlueSQL that integrates seamlessly with a Git repository, allowing you to version-control your data directly within Git. This storage option automatically handles add and commit operations, ensuring your data changes are tracked. For remote operations like pull and push, GitStorage provides methods that developers can manually invoke, giving you full control over synchronization with remote repositories."),(0,r.yg)("h3",{id:"mongo-storage"},"Mongo Storage"),(0,r.yg)("p",null,"With Mongo storage, you can use mongodb as a storage for SQL queries. You can use all the features supported by GlueSQL, such as aggregations and joins, which were previously difficult to handle on an unstructured database. In particular, you can use GlueSQL's powerful schema system on mongodb, which is as strong as an RDBMS."),(0,r.yg)("h3",{id:"web-storage"},"Web Storage"),(0,r.yg)("p",null,"WebStorage, specifically localStorage and sessionStorage, can be used as a data storage system for GlueSQL. While WebStorage is a simple key-value database that uses string keys, GlueSQL makes it more powerful by adding support for SQL queries. This allows you to use SQL to interact with WebStorage, making it a convenient option for developers who are familiar with SQL. WebStorage can be used in JavaScript (Web) environments and Rust WebAssembly environments."),(0,r.yg)("h3",{id:"indexeddb-storage"},"IndexedDB Storage"),(0,r.yg)("p",null,"IndexedDB Storage is a powerful storage system that allows you to interact with IndexedDB using SQL. While using IndexedDB directly can be challenging, GlueSQL makes it easy to use by handling version management internally and storing data in JSON format. With GlueSQL, you can use SQL to interact with IndexedDB, making it a convenient option for developers who are familiar with SQL. You can use IndexedDB Storage in both JavaScript (Web) and Rust WebAssembly environments."),(0,r.yg)("h3",{id:"composite-storage"},"Composite Storage"),(0,r.yg)("p",null,"Composite Storage is a powerful feature of GlueSQL that allows you to bundle together multiple existing storages, enabling you to perform JOIN operations across two distinct storages. This feature is utilized in various environments, including GlueSQL's JavaScript (Web) interface. Specifically, GlueSQL bundles together memory, localStorage, sessionStorage, and IndexedDB using Composite Storage in its JavaScript (Web) interface. This allows you to create tables using four different storages and perform operations like JOIN using SQL, all at once. Composite Storage is a versatile feature that can be used in many different scenarios, making it a valuable tool for developers who need to work with multiple storage systems, including those that require data migration between different storage systems."),(0,r.yg)("h2",{id:"adapting-gluesql-to-your-environment-creating-custom-storage"},"Adapting GlueSQL to Your Environment: Creating Custom Storage"),(0,r.yg)("p",null,"GlueSQL is designed to be adaptable to a wide variety of environments, including file systems, key-value databases, complex NoSQL databases, and remote APIs. To create a custom storage for GlueSQL, you only need to implement the Store and StoreMut traits provided by GlueSQL. These traits allow you to support SELECT queries and modify data, such as INSERT, UPDATE, and DELETE."),(0,r.yg)("p",null,"If you want to support additional features, such as schema changes, transactions, or custom functions, you can implement the corresponding traits. However, these traits are optional, and you can choose to implement only the ones that are relevant to your storage system."),(0,r.yg)("p",null,"To make it even easier to develop custom storages, GlueSQL provides a Test Suite that allows you to test your storage implementation against a set of standard SQL queries. This ensures that your storage system is compatible with GlueSQL and can handle common SQL operations."),(0,r.yg)("p",null,"Overall, creating a custom storage for GlueSQL is a straightforward process that allows you to adapt SQL and the AST Builder to your environment with ease."),(0,r.yg)("h2",{id:"gluesql-custom-storage-let-us-handle-it-for-you"},"GlueSQL Custom Storage: Let Us Handle It for You"),(0,r.yg)("p",null,"Although anyone can develop a custom storage for GlueSQL with ease, our GlueSQL team can also implement and maintain it for you. This is especially recommended for NoSQL databases with their own query planner and execution layer, as adapting GlueSQL to them requires a deep understanding of GlueSQL's planner and storage layer details. We welcome not only database companies but also any services that want to support SQL and GlueSQL query interfaces. As GlueSQL is rapidly adding and improving features, we can help you develop and manage your custom storage effectively if you entrust it to us. If you're interested, please contact us at ",(0,r.yg)("a",{parentName:"p",href:"mailto:taehoon@gluesql.com"},"taehoon@gluesql.com"),"."),(0,r.yg)("h2",{id:"contribution"},"Contribution"),(0,r.yg)("p",null,"GlueSQL is a database project that is simpler than you might think. You only need to know three common Rust project commands: ",(0,r.yg)("inlineCode",{parentName:"p"},"cargo fmt"),", ",(0,r.yg)("inlineCode",{parentName:"p"},"cargo clippy"),", and ",(0,r.yg)("inlineCode",{parentName:"p"},"cargo test"),". Don't hesitate to make pull requests and change the code as you see fit. We have set up GitHub Actions to validate your changes, so you don't have to worry about making mistakes. The line coverage of GlueSQL's core code is almost 99%, which is the result of not only careful test writing, but also of making the test suite easy to understand and use for anyone, even those who are not familiar with Rust. If you're not sure where to start, we recommend exploring the test suite first. Take a look at the existing features and try to understand how they work. Even if you're not familiar with Rust, you should be able to navigate the test suite without any problems. If there's a feature you'd like to see but isn't there yet, implementing it yourself and contributing it to GlueSQL is a great way to get involved. You can also check out the issues on the GlueSQL GitHub repository for more ideas on how to contribute."),(0,r.yg)("h2",{id:"license"},"License"),(0,r.yg)("p",null,"This project is licensed under the Apache License, Version 2.0 - see the ",(0,r.yg)("a",{parentName:"p",href:"https://raw.githubusercontent.com/gluesql/gluesql/main/LICENSE"},"LICENSE")," file for details."))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/c3b79ba0.05e34179.js b/docs/0.16.0/assets/js/c3b79ba0.05e34179.js new file mode 100644 index 00000000..ead67666 --- /dev/null +++ b/docs/0.16.0/assets/js/c3b79ba0.05e34179.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[1570],{3786:s=>{s.exports=JSON.parse('{"permalink":"/docs/0.16.0/blog/tags/nosql","page":1,"postsPerPage":10,"totalPages":1,"totalCount":1,"blogDescription":"Blog","blogTitle":"Blog"}')}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/c5b25a7c.95edb7f7.js b/docs/0.16.0/assets/js/c5b25a7c.95edb7f7.js new file mode 100644 index 00000000..6bbbeac3 --- /dev/null +++ b/docs/0.16.0/assets/js/c5b25a7c.95edb7f7.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[6247],{5680:(e,t,n)=>{n.d(t,{xA:()=>p,yg:()=>m});var r=n(6540);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function l(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},o=Object.keys(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var i=r.createContext({}),c=function(e){var t=r.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},p=function(e){var t=c(e.components);return r.createElement(i.Provider,{value:t},e.children)},u="mdxType",g={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},y=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,i=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=c(n),y=a,m=u["".concat(i,".").concat(y)]||u[y]||g[y]||o;return n?r.createElement(m,l(l({ref:t},p),{},{components:n})):r.createElement(m,l({ref:t},p))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,l=new Array(o);l[0]=y;var s={};for(var i in t)hasOwnProperty.call(t,i)&&(s[i]=t[i]);s.originalType=e,s[u]="string"==typeof e?e:a,l[1]=s;for(var c=2;c<o;c++)l[c]=n[c];return r.createElement.apply(null,l)}return r.createElement.apply(null,n)}y.displayName="MDXCreateElement"},7516:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>i,contentTitle:()=>l,default:()=>g,frontMatter:()=>o,metadata:()=>s,toc:()=>c});var r=n(8168),a=(n(6540),n(5680));const o={},l="CONCAT_WS",s={unversionedId:"sql-syntax/functions/text/concat-ws",id:"sql-syntax/functions/text/concat-ws",title:"CONCAT_WS",description:"The CONCAT_WS function in SQL concatenates two or more strings into one string with a separator.",source:"@site/docs/sql-syntax/functions/text/concat-ws.md",sourceDirName:"sql-syntax/functions/text",slug:"/sql-syntax/functions/text/concat-ws",permalink:"/docs/0.16.0/sql-syntax/functions/text/concat-ws",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"CHR",permalink:"/docs/0.16.0/sql-syntax/functions/text/chr"},next:{title:"CONCAT",permalink:"/docs/0.16.0/sql-syntax/functions/text/concat"}},i={},c=[{value:"Syntax",id:"syntax",level:2},{value:"Parameters",id:"parameters",level:2},{value:"Examples",id:"examples",level:2}],p={toc:c},u="wrapper";function g(e){let{components:t,...n}=e;return(0,a.yg)(u,(0,r.A)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"concat_ws"},"CONCAT_WS"),(0,a.yg)("p",null,"The CONCAT_WS function in SQL concatenates two or more strings into one string with a separator. "),(0,a.yg)("h2",{id:"syntax"},"Syntax"),(0,a.yg)("p",null,"The syntax for the CONCAT_WS function in SQL is:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"CONCAT_WS ( separator, string1, string2, ..., stringN )\n")),(0,a.yg)("h2",{id:"parameters"},"Parameters"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"separator"),": This is the string that will be placed between each string to be concatenated."),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"string1"),", ",(0,a.yg)("inlineCode",{parentName:"li"},"string2"),", ..., ",(0,a.yg)("inlineCode",{parentName:"li"},"stringN"),": These are the strings that you wish to concatenate together. ")),(0,a.yg)("h2",{id:"examples"},"Examples"),(0,a.yg)("p",null,"Let's consider a few examples to understand how to use the CONCAT_WS function."),(0,a.yg)("p",null,"To concatenate strings with a comma separator:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"VALUES(CONCAT_WS(',', 'AB', 'CD', 'EF'));\n")),(0,a.yg)("p",null,"This will return ",(0,a.yg)("inlineCode",{parentName:"p"},"'AB,CD,EF'"),"."),(0,a.yg)("p",null,"You can also concatenate more than two strings:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT CONCAT_WS('/', 'ab', 'cd', 'ef') AS myconcat;\n")),(0,a.yg)("p",null,"This will return ",(0,a.yg)("inlineCode",{parentName:"p"},"'ab/cd/ef'"),"."),(0,a.yg)("p",null,"The CONCAT_WS function will skip any NULL values:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT CONCAT_WS('', 'ab', 'cd', NULL, 'ef') AS myconcat;\n")),(0,a.yg)("p",null,"This will return ",(0,a.yg)("inlineCode",{parentName:"p"},"'abcdef'"),"."),(0,a.yg)("p",null,"The CONCAT_WS function can also take non-string arguments:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT CONCAT_WS('', 123, 456, 3.14) AS myconcat;\n")),(0,a.yg)("p",null,"This will return ",(0,a.yg)("inlineCode",{parentName:"p"},"'1234563.14'"),". In this case, the integers and float values are implicitly converted to strings before concatenation."),(0,a.yg)("p",null,"However, the CONCAT_WS function expects at least two arguments. If fewer than two arguments are passed to the CONCAT_WS function, it will throw an error:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT CONCAT_WS() AS myconcat;\n")),(0,a.yg)("p",null,"This will throw an error because the CONCAT_WS function expects at least two arguments."))}g.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/c5c08033.3258f7d1.js b/docs/0.16.0/assets/js/c5c08033.3258f7d1.js new file mode 100644 index 00000000..e2f5798c --- /dev/null +++ b/docs/0.16.0/assets/js/c5c08033.3258f7d1.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[2100],{5680:(e,t,l)=>{l.d(t,{xA:()=>h,yg:()=>c});var a=l(6540);function r(e,t,l){return t in e?Object.defineProperty(e,t,{value:l,enumerable:!0,configurable:!0,writable:!0}):e[t]=l,e}function i(e,t){var l=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),l.push.apply(l,a)}return l}function g(e){for(var t=1;t<arguments.length;t++){var l=null!=arguments[t]?arguments[t]:{};t%2?i(Object(l),!0).forEach((function(t){r(e,t,l[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(l)):i(Object(l)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(l,t))}))}return e}function n(e,t){if(null==e)return{};var l,a,r=function(e,t){if(null==e)return{};var l,a,r={},i=Object.keys(e);for(a=0;a<i.length;a++)l=i[a],t.indexOf(l)>=0||(r[l]=e[l]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a<i.length;a++)l=i[a],t.indexOf(l)>=0||Object.prototype.propertyIsEnumerable.call(e,l)&&(r[l]=e[l])}return r}var u=a.createContext({}),p=function(e){var t=a.useContext(u),l=t;return e&&(l="function"==typeof e?e(t):g(g({},t),e)),l},h=function(e){var t=p(e.components);return a.createElement(u.Provider,{value:t},e.children)},s="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},o=a.forwardRef((function(e,t){var l=e.components,r=e.mdxType,i=e.originalType,u=e.parentName,h=n(e,["components","mdxType","originalType","parentName"]),s=p(l),o=r,c=s["".concat(u,".").concat(o)]||s[o]||m[o]||i;return l?a.createElement(c,g(g({ref:t},h),{},{components:l})):a.createElement(c,g({ref:t},h))}));function c(e,t){var l=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=l.length,g=new Array(i);g[0]=o;var n={};for(var u in t)hasOwnProperty.call(t,u)&&(n[u]=t[u]);n.originalType=e,n[s]="string"==typeof e?e:r,g[1]=n;for(var p=2;p<i;p++)g[p]=l[p];return a.createElement.apply(null,g)}return a.createElement.apply(null,l)}o.displayName="MDXCreateElement"},2172:(e,t,l)=>{l.r(t),l.d(t,{assets:()=>u,contentTitle:()=>g,default:()=>m,frontMatter:()=>i,metadata:()=>n,toc:()=>p});var a=l(8168),r=(l(6540),l(5680));const i={title:"Release v0.15",description:"Release Note - v0.15",slug:"release-v0.15",authors:[{name:"Taehoon Moon",title:"Creator of GlueSQL",url:"https://github.com/panarch",image_url:"https://github.com/panarch.png"}],tags:["v0.15","release-note"]},g=void 0,n={permalink:"/docs/0.16.0/blog/release-v0.15",source:"@site/blog/2023-11-18-release-v0.15.md",title:"Release v0.15",description:"Release Note - v0.15",date:"2023-11-18T00:00:00.000Z",formattedDate:"November 18, 2023",tags:[{label:"v0.15",permalink:"/docs/0.16.0/blog/tags/v-0-15"},{label:"release-note",permalink:"/docs/0.16.0/blog/tags/release-note"}],readingTime:5.93,hasTruncateMarker:!1,authors:[{name:"Taehoon Moon",title:"Creator of GlueSQL",url:"https://github.com/panarch",image_url:"https://github.com/panarch.png",imageURL:"https://github.com/panarch.png"}],frontMatter:{title:"Release v0.15",description:"Release Note - v0.15",slug:"release-v0.15",authors:[{name:"Taehoon Moon",title:"Creator of GlueSQL",url:"https://github.com/panarch",image_url:"https://github.com/panarch.png",imageURL:"https://github.com/panarch.png"}],tags:["v0.15","release-note"]},nextItem:{title:"GlueSQL - Revolutionizing Databases by Unifying Query Interfaces",permalink:"/docs/0.16.0/blog/revolutionizing-databases-by-unifying-query-interfaces"}},u={authorsImageUrls:[void 0]},p=[{value:"\ud83c\udf0a Breaking Changes",id:"-breaking-changes",level:2},{value:"\ud83c\udf40 Python Support",id:"-python-support",level:3},{value:"Code Samples",id:"code-samples",level:4},{value:"\ud83c\udf40 Redis Storage",id:"-redis-storage",level:3},{value:"\ud83c\udf40 CSV Storage",id:"-csv-storage",level:3},{value:"\ud83c\udf40 More operators and functions",id:"-more-operators-and-functions",level:3},{value:"\ud83d\ude80 Features",id:"-features",level:2},{value:"\ud83c\udf1f Improvements",id:"-improvements",level:2},{value:"\ud83d\udc1b Bug Fixes",id:"-bug-fixes",level:2},{value:"\ud83d\udc4f New Contributors",id:"-new-contributors",level:2}],h={toc:p},s="wrapper";function m(e){let{components:t,...l}=e;return(0,r.yg)(s,(0,a.A)({},h,l,{components:t,mdxType:"MDXLayout"}),(0,r.yg)("h2",{id:"-breaking-changes"},"\ud83c\udf0a Breaking Changes"),(0,r.yg)("h3",{id:"-python-support"},"\ud83c\udf40 Python Support"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"https://pypi.org/project/gluesql/"},"https://pypi.org/project/gluesql/"))),(0,r.yg)("h4",{id:"code-samples"},"Code Samples"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-python"},'from gluesql import Glue, MemoryStorage\nfrom tabulate import tabulate\n\ndb = Glue(MemoryStorage())\n\nsql = """\n SELECT\n u.name as user,\n d.name as device\n FROM User u\n JOIN Device d ON u.id = d.userId\n""".strip().replace(\n " ", ""\n)\n\nresult = db.query(sql)\nrows = result[0].get("rows")\nprint(f"\\n[Query]\\n{sql}")\nprint(tabulate(rows, headers="keys", showindex=True, tablefmt="simple_outline"))\n')),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"feat: Implement Python Binding ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/jopemachine"},"@jopemachine")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1357"},"#1357"),")")),(0,r.yg)("h3",{id:"-redis-storage"},"\ud83c\udf40 Redis Storage"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Feature: redis storage ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gurugio"},"@gurugio")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1396"},"#1396"),")")),(0,r.yg)("h3",{id:"-csv-storage"},"\ud83c\udf40 CSV Storage"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Add CsvStorage support to CLI \\& Rust package ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1437"},"#1437"),")"),(0,r.yg)("li",{parentName:"ul"},"Implement CSV Storage, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1280"},"#1280"),")")),(0,r.yg)("h3",{id:"-more-operators-and-functions"},"\ud83c\udf40 More operators and functions"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"feat: add index","_","by node ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/seonghun-dev"},"@seonghun-dev")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1355"},"#1355"),")"),(0,r.yg)("li",{parentName:"ul"},"Implement DEDUP function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/jinlee0"},"@jinlee0")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1430"},"#1430"),")"),(0,r.yg)("li",{parentName:"ul"},"Bitwise Shift Right Operator Implementation ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/2-NOW"},"@2-NOW")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1394"},"#1394"),")"),(0,r.yg)("li",{parentName:"ul"},"feat: implement ast","_","builder for values function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/tgsong827"},"@tgsong827")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1375"},"#1375"),")"),(0,r.yg)("li",{parentName:"ul"},"Implement ",(0,r.yg)("inlineCode",{parentName:"li"},"ADD_MONTH")," function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/kite707"},"@kite707")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1341"},"#1341"),")"),(0,r.yg)("li",{parentName:"ul"},"Implement ",(0,r.yg)("inlineCode",{parentName:"li"},"SPLICE")," function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/jinlee0"},"@jinlee0")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1371"},"#1371"),")"),(0,r.yg)("li",{parentName:"ul"},"Implement ",(0,r.yg)("inlineCode",{parentName:"li"},"SLICE")," function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/Kwontaehwon"},"@Kwontaehwon")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1340"},"#1340"),")"),(0,r.yg)("li",{parentName:"ul"},"Implement entries in ast builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/2-NOW"},"@2-NOW")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1364"},"#1364"),")"),(0,r.yg)("li",{parentName:"ul"},"Implement GREATEST function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/TheMan1697"},"@TheMan1697")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1312"},"#1312"),")"),(0,r.yg)("li",{parentName:"ul"},"Implement bitwise-not operator (~) in ast builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gurugio"},"@gurugio")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1366"},"#1366"),")"),(0,r.yg)("li",{parentName:"ul"},"Implement COALESCE function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/cake-monotone"},"@cake-monotone")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1333"},"#1333"),")"),(0,r.yg)("li",{parentName:"ul"},"feat: Implement select without table function in ast","_","builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ding-co"},"@ding-co")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1365"},"#1365"),")"),(0,r.yg)("li",{parentName:"ul"},"Add ExprWithAliasNode to ast builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/julia-ing"},"@julia-ing")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1359"},"#1359"),")"),(0,r.yg)("li",{parentName:"ul"},"feat: Implement take function in ast","_","builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ding-co"},"@ding-co")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1346"},"#1346"),")"),(0,r.yg)("li",{parentName:"ul"},"Implement last","_","day function in ast","_","builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/cjy13753"},"@cjy13753")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1344"},"#1344"),")"),(0,r.yg)("li",{parentName:"ul"},"Implement LAST","_","DAY function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1315"},"#1315")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/cjy13753"},"@cjy13753")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1323"},"#1323"),")"),(0,r.yg)("li",{parentName:"ul"},"Implement ast","_","builder for is","_","empty function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/julia-ing"},"@julia-ing")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1337"},"#1337"),")"),(0,r.yg)("li",{parentName:"ul"},"Implement ",(0,r.yg)("inlineCode",{parentName:"li"},"ast_builder")," for skip function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/cl-kim"},"@cl-kim")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1334"},"#1334"),")"),(0,r.yg)("li",{parentName:"ul"},"Implement ENTRIES function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/2-NOW"},"@2-NOW")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1315"},"#1315"),")"),(0,r.yg)("li",{parentName:"ul"},"Feature/operator bit not ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gurugio"},"@gurugio")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1321"},"#1321"),")"),(0,r.yg)("li",{parentName:"ul"},"Implement Skip function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/cl-kim"},"@cl-kim")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1325"},"#1325"),")"),(0,r.yg)("li",{parentName:"ul"},"Implement VALUES function for Map type ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/tgsong827"},"@tgsong827")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1288"},"#1288"),")"),(0,r.yg)("li",{parentName:"ul"},"Feat: impl bitwise-and operation ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/jinlee0"},"@jinlee0")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1281"},"#1281"),")"),(0,r.yg)("li",{parentName:"ul"},"Implement BIT","_","SHIFT","_","LEFT operation ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/codernineteen"},"@codernineteen")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1286"},"#1286"),")"),(0,r.yg)("li",{parentName:"ul"},"implement ",(0,r.yg)("inlineCode",{parentName:"li"},"SORT")," function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/Jaehui-Lee"},"@Jaehui-Lee")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1300"},"#1300"),")"),(0,r.yg)("li",{parentName:"ul"},"feat: Implement ",(0,r.yg)("inlineCode",{parentName:"li"},"LENGTH")," function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/jopemachine"},"@jopemachine")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1298"},"#1298"),")"),(0,r.yg)("li",{parentName:"ul"},"[Function]"," Implement TAKE function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ding-co"},"@ding-co")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1283"},"#1283"),")"),(0,r.yg)("li",{parentName:"ul"},"feat: implement ",(0,r.yg)("inlineCode",{parentName:"li"},"ast_builder")," for replace function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ChobobDev"},"@ChobobDev")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1275"},"#1275"),")"),(0,r.yg)("li",{parentName:"ul"},"feat: implement IS","_","EMPTY function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/julia-ing"},"@julia-ing")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1282"},"#1282"),")"),(0,r.yg)("li",{parentName:"ul"},"[Function]"," Implement REPLACE function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ChobobDev"},"@ChobobDev")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1266"},"#1266"),")"),(0,r.yg)("li",{parentName:"ul"},"Implement MD5 Function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/seonghun-dev"},"@seonghun-dev")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1242"},"#1242"),")"),(0,r.yg)("li",{parentName:"ul"},"[AST Builder]"," Implement ascii, chr function in ast ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/seonghun-dev"},"@seonghun-dev")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1244"},"#1244"),")"),(0,r.yg)("li",{parentName:"ul"},"[AST Builder]"," Implement Geometic Point Type and Geometric Function in AST Builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/seonghun-dev"},"@seonghun-dev")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1222"},"#1222"),")")),(0,r.yg)("h2",{id:"-features"},"\ud83d\ude80 Features"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"feat: implement ",(0,r.yg)("inlineCode",{parentName:"li"},"select")," iterator utility function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1429"},"#1429"),")")),(0,r.yg)("h2",{id:"-improvements"},"\ud83c\udf1f Improvements"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Fix parsing of BigDecimal literals with zero fraction part as floats, not integer ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/zmrdltl"},"@zmrdltl")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1416"},"#1416"),")"),(0,r.yg)("li",{parentName:"ul"},"Update docs/ast-builder padding.md code block lang keyword, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1436"},"#1436"),")"),(0,r.yg)("li",{parentName:"ul"},"Support StoreMut trait to Optional ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/seonghun-dev"},"@seonghun-dev")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1435"},"#1435"),")"),(0,r.yg)("li",{parentName:"ul"},"docs: write docmentation for padding ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1434"},"#1434"),")"),(0,r.yg)("li",{parentName:"ul"},"test: add test cases for astb-padding ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1433"},"#1433"),")"),(0,r.yg)("li",{parentName:"ul"},"Upgrade to chrono v0.4.31 and adjust millisecond value in Timestamp Creation ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/zmrdltl"},"@zmrdltl")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1427"},"#1427"),")"),(0,r.yg)("li",{parentName:"ul"},"Remove unnecessary comments in evalaute/function.rs ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1431"},"#1431"),")"),(0,r.yg)("li",{parentName:"ul"},"write docmentation for character","_","conversion ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1428"},"#1428"),")"),(0,r.yg)("li",{parentName:"ul"},"docs: Add ",(0,r.yg)("inlineCode",{parentName:"li"},"SLICE")," function doc ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/fregataa"},"@fregataa")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1425"},"#1425"),")"),(0,r.yg)("li",{parentName:"ul"},"test: add cases to character","_","conversion ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1424"},"#1424"),")"),(0,r.yg)("li",{parentName:"ul"},"docs:Add doc about SPLICE function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/jinlee0"},"@jinlee0")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1423"},"#1423"),")"),(0,r.yg)("li",{parentName:"ul"},"Change store RowIter type from Iterator to Stream ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1419"},"#1419"),")"),(0,r.yg)("li",{parentName:"ul"},"Reflect Deprecation of ",(0,r.yg)("inlineCode",{parentName:"li"},"from_utc")," in Crate ",(0,r.yg)("inlineCode",{parentName:"li"},"chrono")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/zmrdltl"},"@zmrdltl")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1415"},"#1415"),")"),(0,r.yg)("li",{parentName:"ul"},"Remove eval","_","to","_","{int|float..} macro uses in core/../evaluate/function.rs, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1361"},"#1361"),")"),(0,r.yg)("li",{parentName:"ul"},"test: write example for ast builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/daengdaengLee"},"@daengdaengLee")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1259"},"#1259"),")"),(0,r.yg)("li",{parentName:"ul"},"Fix merge conflict in data/value/mod.rs ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1406"},"#1406"),")"),(0,r.yg)("li",{parentName:"ul"},"chore: implement ",(0,r.yg)("inlineCode",{parentName:"li"},"ConvertError"),", ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1401"},"#1401"),")"),(0,r.yg)("li",{parentName:"ul"},"refactor: remove implementation of from Value trait for Evaluated ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/tgsong827"},"@tgsong827")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1399"},"#1399"),")"),(0,r.yg)("li",{parentName:"ul"},"refactor: update function module's namespacing in ast","_","builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/tgsong827"},"@tgsong827")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1398"},"#1398"),")"),(0,r.yg)("li",{parentName:"ul"},"chore: remove ",(0,r.yg)("inlineCode",{parentName:"li"},"Result")," from ",(0,r.yg)("inlineCode",{parentName:"li"},"ast_builder::transaction")," return type ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1404"},"#1404"),")"),(0,r.yg)("li",{parentName:"ul"},"chore: bump rust version to 1.72 ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1388"},"#1388"),")"),(0,r.yg)("li",{parentName:"ul"},"chore: add example of convert from payload to custom struct ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1379"},"#1379"),")"),(0,r.yg)("li",{parentName:"ul"},"Update Chrono version to 0.4.26, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1374"},"#1374"),")"),(0,r.yg)("li",{parentName:"ul"},"Update test-suite Tester::run to return Payload, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1373"},"#1373"),")"),(0,r.yg)("li",{parentName:"ul"},"Remove .unwrap() uses in test-suite/ test codes, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1372"},"#1372"),")"),(0,r.yg)("li",{parentName:"ul"},"Replace run!, test! and count! macros in test-suite to Tester methods, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1368"},"#1368"),")"),(0,r.yg)("li",{parentName:"ul"},"Update coverage.yml gh-action to ignore await only lines, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1370"},"#1370"),")"),(0,r.yg)("li",{parentName:"ul"},"Apply pretty","_","assertions::assert","_","eq! to core/ ast","_","builder unit tests ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1369"},"#1369"),")"),(0,r.yg)("li",{parentName:"ul"},"Simplify value evaluate cmp with literal ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1353"},"#1353"),")"),(0,r.yg)("li",{parentName:"ul"},"Update gh-action author assign - add zmrdltl to reviewers ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1342"},"#1342"),")"),(0,r.yg)("li",{parentName:"ul"},"Refactor GCD and LCM functions ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/cake-monotone"},"@cake-monotone")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1331"},"#1331"),")"),(0,r.yg)("li",{parentName:"ul"},"Refactor write","_","rows ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1319"},"#1319"),")"),(0,r.yg)("li",{parentName:"ul"},"Js pkg wasm pack build not to generate readme and packagejson ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1327"},"#1327"),")"),(0,r.yg)("li",{parentName:"ul"},"Update pkg/javascript dist directories to use dist","_","web/ and dist","_","node\u2026 ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1326"},"#1326"),")"),(0,r.yg)("li",{parentName:"ul"},"Upgrade bigdecimal to 0.4.1, sqlparser to 0.36.1 ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/jinlee0"},"@jinlee0")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1322"},"#1322"),")"),(0,r.yg)("li",{parentName:"ul"},"Update wasm-pack-action version to 0.4.0, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1316"},"#1316"),")"),(0,r.yg)("li",{parentName:"ul"},"Update JavaScript package load","_","indexeddb method to get namespace as a\u2026 ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1320"},"#1320"),")"),(0,r.yg)("li",{parentName:"ul"},"Upgrade sqlparser-rs version to 0.35, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1292"},"#1292"),")"),(0,r.yg)("li",{parentName:"ul"},"Remove unused error variant in JsonStorage ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1278"},"#1278"),")"),(0,r.yg)("li",{parentName:"ul"},"Implement CAST text literal or value to MAP or LIST, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1267"},"#1267"),")"),(0,r.yg)("li",{parentName:"ul"},"Simplity JsonStorage Store::fetch","_","all","_","schemas codes, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1264"},"#1264"),")"),(0,r.yg)("li",{parentName:"ul"},"Change console.log in gluesql.js -> console.debug ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/parkma99"},"@parkma99")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1256"},"#1256"),")"),(0,r.yg)("li",{parentName:"ul"},"Replace ",(0,r.yg)("inlineCode",{parentName:"li"},"actions-rs/toolchain")," with ",(0,r.yg)("inlineCode",{parentName:"li"},"dtolnay/rust-toolchain")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/jongwooo"},"@jongwooo")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1251"},"#1251"),")"),(0,r.yg)("li",{parentName:"ul"},"ci: Automatically assign a PR to its author ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/rapsealk"},"@rapsealk")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1253"},"#1253"),")"),(0,r.yg)("li",{parentName:"ul"},"Remove sync methods in core/ Glue struct, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1247"},"#1247"),")"),(0,r.yg)("li",{parentName:"ul"},"Remove test function in test-suite tester, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1246"},"#1246"),")"),(0,r.yg)("li",{parentName:"ul"},"fix: allow interval cast-related functions to accept only literals instead of evaluations ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1238"},"#1238"),")"),(0,r.yg)("li",{parentName:"ul"},"Split custom Partial{Eq|Ord} impl of Value \\& Literal into evaluate","_","{eq|cmp} ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1233"},"#1233"),")"),(0,r.yg)("li",{parentName:"ul"},"Improve example codes formatting ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/jopemachine"},"@jopemachine")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1235"},"#1235"),")"),(0,r.yg)("li",{parentName:"ul"},"feat: fmt list and map ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/Mehrbod2002"},"@Mehrbod2002")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1226"},"#1226"),")"),(0,r.yg)("li",{parentName:"ul"},"Update README.md - add blog article links ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1232"},"#1232"),")"),(0,r.yg)("li",{parentName:"ul"},"Write the blog article - revolutionizing databases by unifying the qu\u2026 ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1231"},"#1231"),")"),(0,r.yg)("li",{parentName:"ul"},"Write the blog article - test driven documentation ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1229"},"#1229"),")"),(0,r.yg)("li",{parentName:"ul"},"Write the blog article - breaking the boundary between sql and nosql \u2026 ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1228"},"#1228"),")"),(0,r.yg)("li",{parentName:"ul"},"Add test and doc for ast-builder::statements::querying::data-aggregation ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1224"},"#1224"),")")),(0,r.yg)("h2",{id:"-bug-fixes"},"\ud83d\udc1b Bug Fixes"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"fix: Literal comparison with BinaryOperator ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ding-co"},"@ding-co")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1397"},"#1397"),")"),(0,r.yg)("li",{parentName:"ul"},"fix: update Key.cmp to compare a type with other type ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/tgsong827"},"@tgsong827")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1367"},"#1367"),")"),(0,r.yg)("li",{parentName:"ul"},"Fix Value::evaluate","_","cmp","_","with","_","literal between Decimal and Literal::Num\u2026 ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1352"},"#1352"),")"),(0,r.yg)("li",{parentName:"ul"},"Fix spool on ",(0,r.yg)("inlineCode",{parentName:"li"},"tabular off")," and ",(0,r.yg)("inlineCode",{parentName:"li"},"SelectMap")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1314"},"#1314"),")"),(0,r.yg)("li",{parentName:"ul"},"Update auto-assign-action to be triggered on PR open from fork repos ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1313"},"#1313"),")"),(0,r.yg)("li",{parentName:"ul"},"Fix Scala Subquery should contain only 1 column ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ChobobDev"},"@ChobobDev")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1284"},"#1284"),")"),(0,r.yg)("li",{parentName:"ul"},"Wrap config path by quotes in auto-author-assign.yml ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1258"},"#1258"),")"),(0,r.yg)("li",{parentName:"ul"},"Apply word-wrap to docs/ article h1 ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1230"},"#1230"),")"),(0,r.yg)("li",{parentName:"ul"},"Fix docusaurus.config.js themeConfig handler ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1225"},"#1225"),")")),(0,r.yg)("h2",{id:"-new-contributors"},"\ud83d\udc4f New Contributors"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"https://github.com/Mehrbod2002"},"@Mehrbod2002")," made their first contribution in ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1226"},"https://github.com/gluesql/gluesql/pull/1226")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"https://github.com/jopemachine"},"@jopemachine")," made their first contribution in ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1235"},"https://github.com/gluesql/gluesql/pull/1235")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"https://github.com/rapsealk"},"@rapsealk")," made their first contribution in ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1253"},"https://github.com/gluesql/gluesql/pull/1253")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"https://github.com/parkma99"},"@parkma99")," made their first contribution in ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1256"},"https://github.com/gluesql/gluesql/pull/1256")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"https://github.com/julia-ing"},"@julia-ing")," made their first contribution in ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1282"},"https://github.com/gluesql/gluesql/pull/1282")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"https://github.com/ding-co"},"@ding-co")," made their first contribution in ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1283"},"https://github.com/gluesql/gluesql/pull/1283")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"https://github.com/Jaehui-Lee"},"@Jaehui-Lee")," made their first contribution in ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1300"},"https://github.com/gluesql/gluesql/pull/1300")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"https://github.com/jinlee0"},"@jinlee0")," made their first contribution in ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1322"},"https://github.com/gluesql/gluesql/pull/1322")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"https://github.com/codernineteen"},"@codernineteen")," made their first contribution in ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1286"},"https://github.com/gluesql/gluesql/pull/1286")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"https://github.com/tgsong827"},"@tgsong827")," made their first contribution in ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1288"},"https://github.com/gluesql/gluesql/pull/1288")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"https://github.com/cl-kim"},"@cl-kim")," made their first contribution in ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1325"},"https://github.com/gluesql/gluesql/pull/1325")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"https://github.com/gurugio"},"@gurugio")," made their first contribution in ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1321"},"https://github.com/gluesql/gluesql/pull/1321")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"https://github.com/2-NOW"},"@2-NOW")," made their first contribution in ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1315"},"https://github.com/gluesql/gluesql/pull/1315")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"https://github.com/cake-monotone"},"@cake-monotone")," made their first contribution in ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1331"},"https://github.com/gluesql/gluesql/pull/1331")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"https://github.com/cjy13753"},"@cjy13753")," made their first contribution in ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1323"},"https://github.com/gluesql/gluesql/pull/1323")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"https://github.com/TheMan1697"},"@TheMan1697")," made their first contribution in ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1312"},"https://github.com/gluesql/gluesql/pull/1312")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"https://github.com/Kwontaehwon"},"@Kwontaehwon")," made their first contribution in ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1340"},"https://github.com/gluesql/gluesql/pull/1340")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"https://github.com/kite707"},"@kite707")," made their first contribution in ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1341"},"https://github.com/gluesql/gluesql/pull/1341")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"https://github.com/daengdaengLee"},"@daengdaengLee")," made their first contribution in ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1259"},"https://github.com/gluesql/gluesql/pull/1259")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"https://github.com/fregataa"},"@fregataa")," made their first contribution in ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1425"},"https://github.com/gluesql/gluesql/pull/1425"))),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},"Full Changelog"),": ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/gluesql/gluesql/compare/v0.14.0...v0.15.0"},"https://github.com/gluesql/gluesql/compare/v0.14.0...v0.15.0")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/c5e834bc.7eb47f50.js b/docs/0.16.0/assets/js/c5e834bc.7eb47f50.js new file mode 100644 index 00000000..1ab6f9d9 --- /dev/null +++ b/docs/0.16.0/assets/js/c5e834bc.7eb47f50.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[7700],{5680:(e,t,r)=>{r.d(t,{xA:()=>l,yg:()=>d});var n=r(6540);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function a(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?i(Object(r),!0).forEach((function(t){o(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):i(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function c(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var u=n.createContext({}),s=function(e){var t=n.useContext(u),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},l=function(e){var t=s(e.components);return n.createElement(u.Provider,{value:t},e.children)},p="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},f=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,i=e.originalType,u=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),p=s(r),f=o,d=p["".concat(u,".").concat(f)]||p[f]||m[f]||i;return r?n.createElement(d,a(a({ref:t},l),{},{components:r})):n.createElement(d,a({ref:t},l))}));function d(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=r.length,a=new Array(i);a[0]=f;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c[p]="string"==typeof e?e:o,a[1]=c;for(var s=2;s<i;s++)a[s]=r[s];return n.createElement.apply(null,a)}return n.createElement.apply(null,r)}f.displayName="MDXCreateElement"},5476:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>u,contentTitle:()=>a,default:()=>m,frontMatter:()=>i,metadata:()=>c,toc:()=>s});var n=r(8168),o=(r(6540),r(5680));const i={},a="Trigonometric",c={unversionedId:"ast-builder/functions/math/trigonometric",id:"ast-builder/functions/math/trigonometric",title:"Trigonometric",description:"Todo",source:"@site/docs/ast-builder/functions/math/trigonometric.md",sourceDirName:"ast-builder/functions/math",slug:"/ast-builder/functions/math/trigonometric",permalink:"/docs/0.16.0/ast-builder/functions/math/trigonometric",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"Special Mathematical",permalink:"/docs/0.16.0/ast-builder/functions/math/special-mathematical"},next:{title:"Conversion",permalink:"/docs/0.16.0/ast-builder/functions/date-&-time/conversion"}},u={},s=[{value:"Todo",id:"todo",level:2}],l={toc:s},p="wrapper";function m(e){let{components:t,...r}=e;return(0,o.yg)(p,(0,n.A)({},l,r,{components:t,mdxType:"MDXLayout"}),(0,o.yg)("h1",{id:"trigonometric"},"Trigonometric"),(0,o.yg)("h2",{id:"todo"},"Todo"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre"},"- ACOS: Returns the arc cosine of a number.\n- ASIN: Returns the arc sine of a number.\n- ATAN: Returns the arc tangent of a number.\n- COS: Returns the cosine of a number.\n- SIN: Returns the sine of a number.\n- TAN: Returns the tangent of a number.\n")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/c97e0540.375c7725.js b/docs/0.16.0/assets/js/c97e0540.375c7725.js new file mode 100644 index 00000000..1d69d583 --- /dev/null +++ b/docs/0.16.0/assets/js/c97e0540.375c7725.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[8590],{5680:(e,n,r)=>{r.d(n,{xA:()=>o,yg:()=>d});var t=r(6540);function a(e,n,r){return n in e?Object.defineProperty(e,n,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[n]=r,e}function l(e,n){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var t=Object.getOwnPropertySymbols(e);n&&(t=t.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),r.push.apply(r,t)}return r}function s(e){for(var n=1;n<arguments.length;n++){var r=null!=arguments[n]?arguments[n]:{};n%2?l(Object(r),!0).forEach((function(n){a(e,n,r[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):l(Object(r)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(r,n))}))}return e}function i(e,n){if(null==e)return{};var r,t,a=function(e,n){if(null==e)return{};var r,t,a={},l=Object.keys(e);for(t=0;t<l.length;t++)r=l[t],n.indexOf(r)>=0||(a[r]=e[r]);return a}(e,n);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(t=0;t<l.length;t++)r=l[t],n.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var g=t.createContext({}),u=function(e){var n=t.useContext(g),r=n;return e&&(r="function"==typeof e?e(n):s(s({},n),e)),r},o=function(e){var n=u(e.components);return t.createElement(g.Provider,{value:n},e.children)},p="mdxType",m={inlineCode:"code",wrapper:function(e){var n=e.children;return t.createElement(t.Fragment,{},n)}},c=t.forwardRef((function(e,n){var r=e.components,a=e.mdxType,l=e.originalType,g=e.parentName,o=i(e,["components","mdxType","originalType","parentName"]),p=u(r),c=a,d=p["".concat(g,".").concat(c)]||p[c]||m[c]||l;return r?t.createElement(d,s(s({ref:n},o),{},{components:r})):t.createElement(d,s({ref:n},o))}));function d(e,n){var r=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var l=r.length,s=new Array(l);s[0]=c;var i={};for(var g in n)hasOwnProperty.call(n,g)&&(i[g]=n[g]);i.originalType=e,i[p]="string"==typeof e?e:a,s[1]=i;for(var u=2;u<l;u++)s[u]=r[u];return t.createElement.apply(null,s)}return t.createElement.apply(null,r)}c.displayName="MDXCreateElement"},9573:(e,n,r)=>{r.r(n),r.d(n,{assets:()=>g,contentTitle:()=>s,default:()=>m,frontMatter:()=>l,metadata:()=>i,toc:()=>u});var t=r(8168),a=(r(6540),r(5680));const l={},s="DEGREES",i={unversionedId:"sql-syntax/functions/math/degrees",id:"sql-syntax/functions/math/degrees",title:"DEGREES",description:"The DEGREES function is used to convert a given angle value from radians to degrees. It takes a single numeric argument (angle in radians) and returns the angle in degrees.",source:"@site/docs/sql-syntax/functions/math/degrees.md",sourceDirName:"sql-syntax/functions/math",slug:"/sql-syntax/functions/math/degrees",permalink:"/docs/0.16.0/sql-syntax/functions/math/degrees",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"COS",permalink:"/docs/0.16.0/sql-syntax/functions/math/cos"},next:{title:"DIV",permalink:"/docs/0.16.0/sql-syntax/functions/math/div"}},g={},u=[{value:"Syntax",id:"syntax",level:2},{value:"Examples",id:"examples",level:2},{value:"Example 1: Using DEGREES with float values",id:"example-1-using-degrees-with-float-values",level:3},{value:"Example 2: Using DEGREES with integer values",id:"example-2-using-degrees-with-integer-values",level:3},{value:"Example 3: Using DEGREES with zero",id:"example-3-using-degrees-with-zero",level:3},{value:"Errors",id:"errors",level:2},{value:"Example 4: Using DEGREES with non-numeric values",id:"example-4-using-degrees-with-non-numeric-values",level:3},{value:"Example 5: Using DEGREES with multiple arguments",id:"example-5-using-degrees-with-multiple-arguments",level:3}],o={toc:u},p="wrapper";function m(e){let{components:n,...r}=e;return(0,a.yg)(p,(0,t.A)({},o,r,{components:n,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"degrees"},"DEGREES"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"DEGREES")," function is used to convert a given angle value from radians to degrees. It takes a single numeric argument (angle in radians) and returns the angle in degrees."),(0,a.yg)("h2",{id:"syntax"},"Syntax"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"DEGREES(value)\n")),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"value"),": A numeric expression (angle in radians) to be converted to degrees.")),(0,a.yg)("h2",{id:"examples"},"Examples"),(0,a.yg)("p",null,"Let's consider a table named ",(0,a.yg)("inlineCode",{parentName:"p"},"SingleItem")," with the following schema:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE SingleItem (id FLOAT);\n")),(0,a.yg)("p",null,"Insert a row into the ",(0,a.yg)("inlineCode",{parentName:"p"},"SingleItem")," table:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO SingleItem VALUES (0);\n")),(0,a.yg)("h3",{id:"example-1-using-degrees-with-float-values"},"Example 1: Using DEGREES with float values"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT\nDEGREES(180.0) as degrees_1,\nDEGREES(360.0) as degrees_2\nFROM SingleItem;\n")),(0,a.yg)("p",null,"Result:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre"}," degrees_1 | degrees_2\n-------------+-------------\n10313.240312 | 20626.480624\n")),(0,a.yg)("h3",{id:"example-2-using-degrees-with-integer-values"},"Example 2: Using DEGREES with integer values"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT DEGREES(90) as degrees_with_int FROM SingleItem;\n")),(0,a.yg)("p",null,"Result:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre"},"degrees_with_int\n-----------------\n 5156.620156\n")),(0,a.yg)("h3",{id:"example-3-using-degrees-with-zero"},"Example 3: Using DEGREES with zero"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT DEGREES(0) as degrees_with_zero FROM SingleItem;\n")),(0,a.yg)("p",null,"Result:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre"},"degrees_with_zero\n------------------\n 0.0\n")),(0,a.yg)("h2",{id:"errors"},"Errors"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"DEGREES")," function requires a numeric value as its argument. Using non-numeric values or more than one argument will result in an error."),(0,a.yg)("h3",{id:"example-4-using-degrees-with-non-numeric-values"},"Example 4: Using DEGREES with non-numeric values"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT DEGREES('string') AS degrees FROM SingleItem;\n")),(0,a.yg)("p",null,"Error: Function requires a numeric value."),(0,a.yg)("h3",{id:"example-5-using-degrees-with-multiple-arguments"},"Example 5: Using DEGREES with multiple arguments"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT DEGREES(0, 0) as degrees_arg2 FROM SingleItem;\n")),(0,a.yg)("p",null,"Error: Function expects 1 argument, but 2 were provided."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/c9d1eb08.85ddc867.js b/docs/0.16.0/assets/js/c9d1eb08.85ddc867.js new file mode 100644 index 00000000..a6dd23ea --- /dev/null +++ b/docs/0.16.0/assets/js/c9d1eb08.85ddc867.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[2119],{5680:(e,t,r)=>{r.d(t,{xA:()=>c,yg:()=>y});var n=r(6540);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function l(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?i(Object(r),!0).forEach((function(t){a(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):i(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function o(e,t){if(null==e)return{};var r,n,a=function(e,t){if(null==e)return{};var r,n,a={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var s=n.createContext({}),u=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):l(l({},t),e)),r},c=function(e){var t=u(e.components);return n.createElement(s.Provider,{value:t},e.children)},p="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},g=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,i=e.originalType,s=e.parentName,c=o(e,["components","mdxType","originalType","parentName"]),p=u(r),g=a,y=p["".concat(s,".").concat(g)]||p[g]||m[g]||i;return r?n.createElement(y,l(l({ref:t},c),{},{components:r})):n.createElement(y,l({ref:t},c))}));function y(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=r.length,l=new Array(i);l[0]=g;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[p]="string"==typeof e?e:a,l[1]=o;for(var u=2;u<i;u++)l[u]=r[u];return n.createElement.apply(null,l)}return n.createElement.apply(null,r)}g.displayName="MDXCreateElement"},8315:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>m,frontMatter:()=>i,metadata:()=>o,toc:()=>u});var n=r(8168),a=(r(6540),r(5680));const i={},l="RTRIM",o={unversionedId:"sql-syntax/functions/text/rtrim",id:"sql-syntax/functions/text/rtrim",title:"RTRIM",description:"The RTRIM function in SQL removes characters from the right (trailing side) of a string.",source:"@site/docs/sql-syntax/functions/text/rtrim.md",sourceDirName:"sql-syntax/functions/text",slug:"/sql-syntax/functions/text/rtrim",permalink:"/docs/0.16.0/sql-syntax/functions/text/rtrim",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"RPAD",permalink:"/docs/0.16.0/sql-syntax/functions/text/rpad"},next:{title:"SUBSTR",permalink:"/docs/0.16.0/sql-syntax/functions/text/substr"}},s={},u=[{value:"Syntax",id:"syntax",level:2},{value:"Parameters",id:"parameters",level:2},{value:"Return Value",id:"return-value",level:2},{value:"Errors",id:"errors",level:2},{value:"Examples",id:"examples",level:2}],c={toc:u},p="wrapper";function m(e){let{components:t,...r}=e;return(0,a.yg)(p,(0,n.A)({},c,r,{components:t,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"rtrim"},"RTRIM"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"RTRIM")," function in SQL removes characters from the right (trailing side) of a string."),(0,a.yg)("h2",{id:"syntax"},"Syntax"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"RTRIM(string, trim_string)\n")),(0,a.yg)("h2",{id:"parameters"},"Parameters"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"string"),": The original string to trim."),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"trim_string")," (optional): The characters to remove from the string. If not supplied, spaces are removed.")),(0,a.yg)("h2",{id:"return-value"},"Return Value"),(0,a.yg)("p",null,"The function returns a new string that is the same as the original string, but without the specified trailing characters."),(0,a.yg)("h2",{id:"errors"},"Errors"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},"If the ",(0,a.yg)("inlineCode",{parentName:"li"},"string")," or ",(0,a.yg)("inlineCode",{parentName:"li"},"trim_string")," argument is not a string, a ",(0,a.yg)("inlineCode",{parentName:"li"},"FunctionRequiresStringValue")," error will be returned.")),(0,a.yg)("h2",{id:"examples"},"Examples"),(0,a.yg)("p",null,"Consider a table ",(0,a.yg)("inlineCode",{parentName:"p"},"Item")," created and filled with the following data:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE Item (\n name TEXT\n);\nINSERT INTO Item VALUES ('testxxzx ');\n")),(0,a.yg)("p",null,"You can use the ",(0,a.yg)("inlineCode",{parentName:"p"},"RTRIM")," function to remove trailing spaces from the ",(0,a.yg)("inlineCode",{parentName:"p"},"name")," values:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT RTRIM(name) AS trimmed_name FROM Item;\n")),(0,a.yg)("p",null,"This will return:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre"},"testxxzx\n")),(0,a.yg)("p",null,"You can also specify a string of characters to remove. The function will remove any character in this string from the end of the original string:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT RTRIM(name, 'zx ') AS trimmed_name FROM Item;\n")),(0,a.yg)("p",null,"This will return:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre"},"test\n")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/ca8fbf24.d1ac6d6a.js b/docs/0.16.0/assets/js/ca8fbf24.d1ac6d6a.js new file mode 100644 index 00000000..2e8486df --- /dev/null +++ b/docs/0.16.0/assets/js/ca8fbf24.d1ac6d6a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[7807],{8707:s=>{s.exports=JSON.parse('{"permalink":"/docs/0.16.0/blog/tags/chat-gpt","page":1,"postsPerPage":10,"totalPages":1,"totalCount":1,"blogDescription":"Blog","blogTitle":"Blog"}')}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/cba69ead.8298012c.js b/docs/0.16.0/assets/js/cba69ead.8298012c.js new file mode 100644 index 00000000..b3907d56 --- /dev/null +++ b/docs/0.16.0/assets/js/cba69ead.8298012c.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[9544],{7350:s=>{s.exports=JSON.parse('{"permalink":"/docs/0.16.0/blog/tags/v-0-15","page":1,"postsPerPage":10,"totalPages":1,"totalCount":1,"blogDescription":"Blog","blogTitle":"Blog"}')}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/ccc49370.db557050.js b/docs/0.16.0/assets/js/ccc49370.db557050.js new file mode 100644 index 00000000..9e982319 --- /dev/null +++ b/docs/0.16.0/assets/js/ccc49370.db557050.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[3249],{4029:(e,t,n)=>{n.r(t),n.d(t,{default:()=>h});var a=n(6540),l=n(53),o=n(1003),r=n(7559),i=n(7131),c=n(6669),s=n(8258),m=n(8168),d=n(1312),u=n(9022);function g(e){const{nextItem:t,prevItem:n}=e;return a.createElement("nav",{className:"pagination-nav docusaurus-mt-lg","aria-label":(0,d.T)({id:"theme.blog.post.paginator.navAriaLabel",message:"Blog post page navigation",description:"The ARIA label for the blog posts pagination"})},n&&a.createElement(u.A,(0,m.A)({},n,{subLabel:a.createElement(d.A,{id:"theme.blog.post.paginator.newerPost",description:"The blog post button label to navigate to the newer/previous post"},"Newer Post")})),t&&a.createElement(u.A,(0,m.A)({},t,{subLabel:a.createElement(d.A,{id:"theme.blog.post.paginator.olderPost",description:"The blog post button label to navigate to the older/next post"},"Older Post"),isNext:!0})))}function f(){const{assets:e,metadata:t}=(0,i.e)(),{title:n,description:l,date:r,tags:c,authors:s,frontMatter:m}=t,{keywords:d}=m,u=e.image??m.image;return a.createElement(o.be,{title:n,description:l,keywords:d,image:u},a.createElement("meta",{property:"og:type",content:"article"}),a.createElement("meta",{property:"article:published_time",content:r}),s.some((e=>e.url))&&a.createElement("meta",{property:"article:author",content:s.map((e=>e.url)).filter(Boolean).join(",")}),c.length>0&&a.createElement("meta",{property:"article:tag",content:c.map((e=>e.label)).join(",")}))}var v=n(7763);function p(e){let{sidebar:t,children:n}=e;const{metadata:l,toc:o}=(0,i.e)(),{nextItem:r,prevItem:m,frontMatter:d}=l,{hide_table_of_contents:u,toc_min_heading_level:f,toc_max_heading_level:p}=d;return a.createElement(c.A,{sidebar:t,toc:!u&&o.length>0?a.createElement(v.A,{toc:o,minHeadingLevel:f,maxHeadingLevel:p}):void 0},a.createElement(s.A,null,n),(r||m)&&a.createElement(g,{nextItem:r,prevItem:m}))}function h(e){const t=e.content;return a.createElement(i.i,{content:e.content,isBlogPostPage:!0},a.createElement(o.e3,{className:(0,l.A)(r.G.wrapper.blogPages,r.G.page.blogPostPage)},a.createElement(f,null),a.createElement(p,{sidebar:e.sidebar},a.createElement(t,null))))}},7763:(e,t,n)=>{n.d(t,{A:()=>m});var a=n(8168),l=n(6540),o=n(53),r=n(5195);const i={tableOfContents:"tableOfContents_bqdL",docItemContainer:"docItemContainer_F8PC"},c="table-of-contents__link toc-highlight",s="table-of-contents__link--active";function m(e){let{className:t,...n}=e;return l.createElement("div",{className:(0,o.A)(i.tableOfContents,"thin-scrollbar",t)},l.createElement(r.A,(0,a.A)({},n,{linkClassName:c,linkActiveClassName:s})))}},5195:(e,t,n)=>{n.d(t,{A:()=>f});var a=n(8168),l=n(6540),o=n(6342);function r(e){const t=e.map((e=>({...e,parentIndex:-1,children:[]}))),n=Array(7).fill(-1);t.forEach(((e,t)=>{const a=n.slice(2,e.level);e.parentIndex=Math.max(...a),n[e.level]=t}));const a=[];return t.forEach((e=>{const{parentIndex:n,...l}=e;n>=0?t[n].children.push(l):a.push(l)})),a}function i(e){let{toc:t,minHeadingLevel:n,maxHeadingLevel:a}=e;return t.flatMap((e=>{const t=i({toc:e.children,minHeadingLevel:n,maxHeadingLevel:a});return function(e){return e.level>=n&&e.level<=a}(e)?[{...e,children:t}]:t}))}function c(e){const t=e.getBoundingClientRect();return t.top===t.bottom?c(e.parentNode):t}function s(e,t){let{anchorTopOffset:n}=t;const a=e.find((e=>c(e).top>=n));if(a){return function(e){return e.top>0&&e.bottom<window.innerHeight/2}(c(a))?a:e[e.indexOf(a)-1]??null}return e[e.length-1]??null}function m(){const e=(0,l.useRef)(0),{navbar:{hideOnScroll:t}}=(0,o.p)();return(0,l.useEffect)((()=>{e.current=t?0:document.querySelector(".navbar").clientHeight}),[t]),e}function d(e){const t=(0,l.useRef)(void 0),n=m();(0,l.useEffect)((()=>{if(!e)return()=>{};const{linkClassName:a,linkActiveClassName:l,minHeadingLevel:o,maxHeadingLevel:r}=e;function i(){const e=function(e){return Array.from(document.getElementsByClassName(e))}(a),i=function(e){let{minHeadingLevel:t,maxHeadingLevel:n}=e;const a=[];for(let l=t;l<=n;l+=1)a.push(`h${l}.anchor`);return Array.from(document.querySelectorAll(a.join()))}({minHeadingLevel:o,maxHeadingLevel:r}),c=s(i,{anchorTopOffset:n.current}),m=e.find((e=>c&&c.id===function(e){return decodeURIComponent(e.href.substring(e.href.indexOf("#")+1))}(e)));e.forEach((e=>{!function(e,n){n?(t.current&&t.current!==e&&t.current.classList.remove(l),e.classList.add(l),t.current=e):e.classList.remove(l)}(e,e===m)}))}return document.addEventListener("scroll",i),document.addEventListener("resize",i),i(),()=>{document.removeEventListener("scroll",i),document.removeEventListener("resize",i)}}),[e,n])}function u(e){let{toc:t,className:n,linkClassName:a,isChild:o}=e;return t.length?l.createElement("ul",{className:o?void 0:n},t.map((e=>l.createElement("li",{key:e.id},l.createElement("a",{href:`#${e.id}`,className:a??void 0,dangerouslySetInnerHTML:{__html:e.value}}),l.createElement(u,{isChild:!0,toc:e.children,className:n,linkClassName:a}))))):null}const g=l.memo(u);function f(e){let{toc:t,className:n="table-of-contents table-of-contents__left-border",linkClassName:c="table-of-contents__link",linkActiveClassName:s,minHeadingLevel:m,maxHeadingLevel:u,...f}=e;const v=(0,o.p)(),p=m??v.tableOfContents.minHeadingLevel,h=u??v.tableOfContents.maxHeadingLevel,b=function(e){let{toc:t,minHeadingLevel:n,maxHeadingLevel:a}=e;return(0,l.useMemo)((()=>i({toc:r(t),minHeadingLevel:n,maxHeadingLevel:a})),[t,n,a])}({toc:t,minHeadingLevel:p,maxHeadingLevel:h});return d((0,l.useMemo)((()=>{if(c&&s)return{linkClassName:c,linkActiveClassName:s,minHeadingLevel:p,maxHeadingLevel:h}}),[c,s,p,h])),l.createElement(g,(0,a.A)({toc:b,className:n,linkClassName:c},f))}}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/cdaafcc9.085c239c.js b/docs/0.16.0/assets/js/cdaafcc9.085c239c.js new file mode 100644 index 00000000..dbb0e413 --- /dev/null +++ b/docs/0.16.0/assets/js/cdaafcc9.085c239c.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[1433],{5680:(e,t,n)=>{n.d(t,{xA:()=>u,yg:()=>g});var r=n(6540);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?a(Object(n),!0).forEach((function(t){o(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):a(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},a=Object.keys(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=r.createContext({}),c=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},u=function(e){var t=c(e.components);return r.createElement(s.Provider,{value:t},e.children)},p="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},f=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,s=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=c(n),f=o,g=p["".concat(s,".").concat(f)]||p[f]||m[f]||a;return n?r.createElement(g,i(i({ref:t},u),{},{components:n})):r.createElement(g,i({ref:t},u))}));function g(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,i=new Array(a);i[0]=f;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[p]="string"==typeof e?e:o,i[1]=l;for(var c=2;c<a;c++)i[c]=n[c];return r.createElement.apply(null,i)}return r.createElement.apply(null,n)}f.displayName="MDXCreateElement"},5682:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>m,frontMatter:()=>a,metadata:()=>l,toc:()=>c});var r=n(8168),o=(n(6540),n(5680));const a={},i="GCD",l={unversionedId:"sql-syntax/functions/math/gcd",id:"sql-syntax/functions/math/gcd",title:"GCD",description:"The GCD function is used to find the greatest common divisor (GCD) of two integers. It takes two INTEGER arguments and returns an INTEGER value representing the greatest common divisor of the given integers.",source:"@site/docs/sql-syntax/functions/math/gcd.md",sourceDirName:"sql-syntax/functions/math",slug:"/sql-syntax/functions/math/gcd",permalink:"/docs/0.16.0/sql-syntax/functions/math/gcd",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"FLOOR",permalink:"/docs/0.16.0/sql-syntax/functions/math/floor"},next:{title:"LCM",permalink:"/docs/0.16.0/sql-syntax/functions/math/lcm"}},s={},c=[{value:"Example",id:"example",level:2},{value:"Errors",id:"errors",level:2}],u={toc:c},p="wrapper";function m(e){let{components:t,...n}=e;return(0,o.yg)(p,(0,r.A)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,o.yg)("h1",{id:"gcd"},"GCD"),(0,o.yg)("p",null,"The ",(0,o.yg)("inlineCode",{parentName:"p"},"GCD")," function is used to find the greatest common divisor (GCD) of two integers. It takes two INTEGER arguments and returns an INTEGER value representing the greatest common divisor of the given integers."),(0,o.yg)("h2",{id:"example"},"Example"),(0,o.yg)("p",null,"The following example demonstrates the usage of the ",(0,o.yg)("inlineCode",{parentName:"p"},"GCD")," function in a SQL query:"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE GcdI64 (\n left INTEGER NULL DEFAULT GCD(3, 4),\n right INTEGER NULL\n);\n\nINSERT INTO GcdI64 VALUES (0, 3), (2, 4), (6, 8), (3, 5), (1, NULL), (NULL, 1);\n\nSELECT GCD(left, right) AS test FROM GcdI64;\n")),(0,o.yg)("p",null,"This will return the following result:"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre"},"test\n3\n2\n2\n1\nNULL\nNULL\n")),(0,o.yg)("h2",{id:"errors"},"Errors"),(0,o.yg)("ol",null,(0,o.yg)("li",{parentName:"ol"},"If either of the arguments is not of INTEGER type, a ",(0,o.yg)("inlineCode",{parentName:"li"},"FunctionRequiresIntegerValue")," error will be raised."),(0,o.yg)("li",{parentName:"ol"},"If the number of arguments provided to the function is not equal to 2, a ",(0,o.yg)("inlineCode",{parentName:"li"},"FunctionArgsLengthNotMatching")," error will be raised."),(0,o.yg)("li",{parentName:"ol"},"If either of the arguments is the minimum i64 value (",(0,o.yg)("inlineCode",{parentName:"li"},"-9223372036854775808"),"), an overflow occurs when attempting to take the absolute value. In this case, a ",(0,o.yg)("inlineCode",{parentName:"li"},"GcdLcmOverflowError")," is raised.")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/cf518063.ebb43726.js b/docs/0.16.0/assets/js/cf518063.ebb43726.js new file mode 100644 index 00000000..db0ca3dd --- /dev/null +++ b/docs/0.16.0/assets/js/cf518063.ebb43726.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[6251],{5680:(e,t,n)=>{n.d(t,{xA:()=>p,yg:()=>g});var a=n(6540);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?l(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):l(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,a,r=function(e,t){if(null==e)return{};var n,a,r={},l=Object.keys(e);for(a=0;a<l.length;a++)n=l[a],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a<l.length;a++)n=l[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var i=a.createContext({}),c=function(e){var t=a.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=c(e.components);return a.createElement(i.Provider,{value:t},e.children)},u="mdxType",y={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,l=e.originalType,i=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=c(n),m=r,g=u["".concat(i,".").concat(m)]||u[m]||y[m]||l;return n?a.createElement(g,o(o({ref:t},p),{},{components:n})):a.createElement(g,o({ref:t},p))}));function g(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var l=n.length,o=new Array(l);o[0]=m;var s={};for(var i in t)hasOwnProperty.call(t,i)&&(s[i]=t[i]);s.originalType=e,s[u]="string"==typeof e?e:r,o[1]=s;for(var c=2;c<l;c++)o[c]=n[c];return a.createElement.apply(null,o)}return a.createElement.apply(null,n)}m.displayName="MDXCreateElement"},8065:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>i,contentTitle:()=>o,default:()=>y,frontMatter:()=>l,metadata:()=>s,toc:()=>c});var a=n(8168),r=(n(6540),n(5680));const l={},o="CONCAT",s={unversionedId:"sql-syntax/functions/list-map/concat",id:"sql-syntax/functions/list-map/concat",title:"CONCAT",description:"The CONCAT function is used to concatenate two or more list values together.",source:"@site/docs/sql-syntax/functions/list-map/concat.md",sourceDirName:"sql-syntax/functions/list-map",slug:"/sql-syntax/functions/list-map/concat",permalink:"/docs/0.16.0/sql-syntax/functions/list-map/concat",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"APPEND",permalink:"/docs/0.16.0/sql-syntax/functions/list-map/append"},next:{title:"PREPEND",permalink:"/docs/0.16.0/sql-syntax/functions/list-map/prepend"}},i={},c=[{value:"Syntax",id:"syntax",level:2},{value:"Examples",id:"examples",level:2},{value:"Example 1: CONCAT two lists",id:"example-1-concat-two-lists",level:3}],p={toc:c},u="wrapper";function y(e){let{components:t,...n}=e;return(0,r.yg)(u,(0,a.A)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,r.yg)("h1",{id:"concat"},"CONCAT"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"CONCAT")," function is used to concatenate two or more list values together."),(0,r.yg)("h2",{id:"syntax"},"Syntax"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"CONCAT(list_value1, list_value2, ...)\n")),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},"Parameters:")),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"list_value1"),", ",(0,r.yg)("inlineCode",{parentName:"li"},"list_value2"),", ...: List values that will be concatenated.")),(0,r.yg)("h2",{id:"examples"},"Examples"),(0,r.yg)("p",null,"Consider the following table ",(0,r.yg)("inlineCode",{parentName:"p"},"ListTypeConcat"),":"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE ListTypeConcat (\n id INTEGER,\n items LIST,\n items2 LIST\n);\n")),(0,r.yg)("p",null,"With the following data:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},'INSERT INTO ListTypeConcat VALUES\n (1, \'[1, 2, 3]\', \'["one", "two", "three"]\');\n')),(0,r.yg)("h3",{id:"example-1-concat-two-lists"},"Example 1: CONCAT two lists"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT CONCAT(items, items2) AS myconcat FROM ListTypeConcat;\n")),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},"Result:")),(0,r.yg)("table",null,(0,r.yg)("thead",{parentName:"table"},(0,r.yg)("tr",{parentName:"thead"},(0,r.yg)("th",{parentName:"tr",align:null},"myconcat"))),(0,r.yg)("tbody",{parentName:"table"},(0,r.yg)("tr",{parentName:"tbody"},(0,r.yg)("td",{parentName:"tr",align:null},'[1, 2, 3, "one", "two", "three"]')))))}y.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/d077f377.2c3c9edc.js b/docs/0.16.0/assets/js/d077f377.2c3c9edc.js new file mode 100644 index 00000000..6a34e3f5 --- /dev/null +++ b/docs/0.16.0/assets/js/d077f377.2c3c9edc.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[6738],{5680:(e,t,n)=>{n.d(t,{xA:()=>c,yg:()=>g});var a=n(6540);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function s(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function i(e,t){if(null==e)return{};var n,a,r=function(e,t){if(null==e)return{};var n,a,r={},o=Object.keys(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=a.createContext({}),u=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},c=function(e){var t=u(e.components);return a.createElement(l.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},y=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,c=i(e,["components","mdxType","originalType","parentName"]),p=u(n),y=r,g=p["".concat(l,".").concat(y)]||p[y]||d[y]||o;return n?a.createElement(g,s(s({ref:t},c),{},{components:n})):a.createElement(g,s({ref:t},c))}));function g(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,s=new Array(o);s[0]=y;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i[p]="string"==typeof e?e:r,s[1]=i;for(var u=2;u<o;u++)s[u]=n[u];return a.createElement.apply(null,s)}return a.createElement.apply(null,n)}y.displayName="MDXCreateElement"},3433:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>s,default:()=>d,frontMatter:()=>o,metadata:()=>i,toc:()=>u});var a=n(8168),r=(n(6540),n(5680));const o={sidebar_position:4},s="TEXT",i={unversionedId:"sql-syntax/data-types/text",id:"sql-syntax/data-types/text",title:"TEXT",description:"The TEXT data type in SQL is used to store variable-length character strings. In GlueSQL, the TEXT data type is the only supported string data type, providing the ability to store and manage strings of varying lengths.",source:"@site/docs/sql-syntax/data-types/text.md",sourceDirName:"sql-syntax/data-types",slug:"/sql-syntax/data-types/text",permalink:"/docs/0.16.0/sql-syntax/data-types/text",draft:!1,tags:[],version:"current",sidebarPosition:4,frontMatter:{sidebar_position:4},sidebar:"autoSidebar",previous:{title:"FLOAT",permalink:"/docs/0.16.0/sql-syntax/data-types/float"},next:{title:"DECIMAL",permalink:"/docs/0.16.0/sql-syntax/data-types/decimal"}},l={},u=[{value:"Creating a table with a TEXT column",id:"creating-a-table-with-a-text-column",level:2},{value:"Inserting data into the TEXT column",id:"inserting-data-into-the-text-column",level:2},{value:"Querying data from the TEXT column",id:"querying-data-from-the-text-column",level:2},{value:"Conclusion",id:"conclusion",level:2}],c={toc:u},p="wrapper";function d(e){let{components:t,...n}=e;return(0,r.yg)(p,(0,a.A)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,r.yg)("h1",{id:"text"},"TEXT"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"TEXT")," data type in SQL is used to store variable-length character strings. In GlueSQL, the TEXT data type is the only supported string data type, providing the ability to store and manage strings of varying lengths."),(0,r.yg)("p",null,"Here's an example of how to create a table, insert data, and query data using the ",(0,r.yg)("inlineCode",{parentName:"p"},"TEXT")," data type:"),(0,r.yg)("h2",{id:"creating-a-table-with-a-text-column"},"Creating a table with a TEXT column"),(0,r.yg)("p",null,"To create a table with a TEXT column, use the following SQL syntax:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE users (username TEXT, email TEXT);\n")),(0,r.yg)("h2",{id:"inserting-data-into-the-text-column"},"Inserting data into the TEXT column"),(0,r.yg)("p",null,"To insert data into the TEXT column, provide the string values:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO users (username, email) VALUES\n ('user1', 'user1@example.com'),\n ('user2', 'user2@example.com'),\n ('user3', 'user3@example.com');\n")),(0,r.yg)("h2",{id:"querying-data-from-the-text-column"},"Querying data from the TEXT column"),(0,r.yg)("p",null,"To query data from the TEXT column, use standard SQL syntax:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT username, email FROM users;\n")),(0,r.yg)("p",null,"This query will return the following result:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre"},"username | email\n---------|-------------------\nuser1 | user1@example.com\nuser2 | user2@example.com\nuser3 | user3@example.com\n")),(0,r.yg)("h2",{id:"conclusion"},"Conclusion"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"TEXT")," data type is a versatile and essential data type for handling and storing character strings in SQL databases. By understanding the basics of the TEXT data type and its use cases, you can effectively use it in your database designs and operations, ensuring that your applications can manage a wide range of textual data with ease."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/d0ba620f.f8ae8564.js b/docs/0.16.0/assets/js/d0ba620f.f8ae8564.js new file mode 100644 index 00000000..026b9568 --- /dev/null +++ b/docs/0.16.0/assets/js/d0ba620f.f8ae8564.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[5334],{5680:(e,n,t)=>{t.d(n,{xA:()=>g,yg:()=>d});var l=t(6540);function a(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function r(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);n&&(l=l.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,l)}return t}function i(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?r(Object(t),!0).forEach((function(n){a(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):r(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function s(e,n){if(null==e)return{};var t,l,a=function(e,n){if(null==e)return{};var t,l,a={},r=Object.keys(e);for(l=0;l<r.length;l++)t=r[l],n.indexOf(t)>=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(l=0;l<r.length;l++)t=r[l],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var o=l.createContext({}),u=function(e){var n=l.useContext(o),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},g=function(e){var n=u(e.components);return l.createElement(o.Provider,{value:n},e.children)},p="mdxType",c={inlineCode:"code",wrapper:function(e){var n=e.children;return l.createElement(l.Fragment,{},n)}},y=l.forwardRef((function(e,n){var t=e.components,a=e.mdxType,r=e.originalType,o=e.parentName,g=s(e,["components","mdxType","originalType","parentName"]),p=u(t),y=a,d=p["".concat(o,".").concat(y)]||p[y]||c[y]||r;return t?l.createElement(d,i(i({ref:n},g),{},{components:t})):l.createElement(d,i({ref:n},g))}));function d(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var r=t.length,i=new Array(r);i[0]=y;var s={};for(var o in n)hasOwnProperty.call(n,o)&&(s[o]=n[o]);s.originalType=e,s[p]="string"==typeof e?e:a,i[1]=s;for(var u=2;u<r;u++)i[u]=t[u];return l.createElement.apply(null,i)}return l.createElement.apply(null,t)}y.displayName="MDXCreateElement"},6103:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>o,contentTitle:()=>i,default:()=>c,frontMatter:()=>r,metadata:()=>s,toc:()=>u});var l=t(8168),a=(t(6540),t(5680));const r={},i="SLICE",s={unversionedId:"sql-syntax/functions/list-map/slice",id:"sql-syntax/functions/list-map/slice",title:"SLICE",description:"The SLICE statement is a function in GlueSQL that allows you to retrieve a subsection of a list. It is analogous to slicing operations in many programming languages.",source:"@site/docs/sql-syntax/functions/list-map/slice.md",sourceDirName:"sql-syntax/functions/list-map",slug:"/sql-syntax/functions/list-map/slice",permalink:"/docs/0.16.0/sql-syntax/functions/list-map/slice",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"PREPEND",permalink:"/docs/0.16.0/sql-syntax/functions/list-map/prepend"},next:{title:'SQL Function - "SPLICE"',permalink:"/docs/0.16.0/sql-syntax/functions/list-map/splice"}},o={},u=[{value:"Syntax",id:"syntax",level:2},{value:"Examples",id:"examples",level:2},{value:"1. Basic Slicing",id:"1-basic-slicing",level:3},{value:"2. Slicing Beyond List Length",id:"2-slicing-beyond-list-length",level:3},{value:"3. Start Index Beyond List Length",id:"3-start-index-beyond-list-length",level:3},{value:"4. Using Negative Start Index",id:"4-using-negative-start-index",level:3},{value:"Errors",id:"errors",level:2}],g={toc:u},p="wrapper";function c(e){let{components:n,...t}=e;return(0,a.yg)(p,(0,l.A)({},g,t,{components:n,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"slice"},"SLICE"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"SLICE")," statement is a function in GlueSQL that allows you to retrieve a subsection of a list. It is analogous to slicing operations in many programming languages."),(0,a.yg)("h2",{id:"syntax"},"Syntax"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT SLICE(column_name, start_index, length) AS alias_name FROM table_name;\n")),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"column_name"),": Name of the column containing the list."),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"start_index"),": The starting index from where the slice should begin. This value can be negative."),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"length"),": The number of elements to be included in the slice.")),(0,a.yg)("h2",{id:"examples"},"Examples"),(0,a.yg)("p",null,"Consider the following table ",(0,a.yg)("inlineCode",{parentName:"p"},"Test"),":"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE Test (\n list LIST\n);\n")),(0,a.yg)("p",null,"With the following data:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO Test VALUES\n('[1,2,3,4]');\n")),(0,a.yg)("h3",{id:"1-basic-slicing"},"1. Basic Slicing"),(0,a.yg)("p",null,"Retrieve the first 2 elements from a list."),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT SLICE(list, 0, 2) AS value FROM Test;\n")),(0,a.yg)("p",null,"Result:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre"},"[1, 2]\n")),(0,a.yg)("h3",{id:"2-slicing-beyond-list-length"},"2. Slicing Beyond List Length"),(0,a.yg)("p",null,"If the combined start index and length exceed the list size, ",(0,a.yg)("inlineCode",{parentName:"p"},"SLICE")," will return all possible elements without error."),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT SLICE(list, 2, 5) AS value FROM Test;\n")),(0,a.yg)("p",null,"Result:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre"},"[3, 4]\n")),(0,a.yg)("h3",{id:"3-start-index-beyond-list-length"},"3. Start Index Beyond List Length"),(0,a.yg)("p",null,"If the start index alone exceeds the list size, ",(0,a.yg)("inlineCode",{parentName:"p"},"SLICE")," will return an empty list."),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT SLICE(list, 100, 5) AS value FROM Test;\n")),(0,a.yg)("p",null,"Result:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre"},"[]\n")),(0,a.yg)("h3",{id:"4-using-negative-start-index"},"4. Using Negative Start Index"),(0,a.yg)("p",null,"A negative start index counts from the end of the list."),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT SLICE(list, -1, 1) AS value FROM Test;\n")),(0,a.yg)("p",null,"Result:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre"},"[4]\n")),(0,a.yg)("p",null,"Another example of a negative start index."),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT SLICE(list, -2, 4) AS value FROM Test;\n")),(0,a.yg)("p",null,"Result:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre"},"[3, 4]\n")),(0,a.yg)("p",null,"If the absolute value of the negative start index exceeds the list length, it is treated as index 0."),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT SLICE(list, -234, 4) AS value FROM Test;\n")),(0,a.yg)("p",null,"Result:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre"},"[1, 2, 3, 4]\n")),(0,a.yg)("h2",{id:"errors"},"Errors"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},"Using a non-list value for slicing will result in an error: ",(0,a.yg)("inlineCode",{parentName:"li"},"ListTypeRequired"),"."),(0,a.yg)("li",{parentName:"ul"},"Using a non-integer value for the start index or length will result in an error: ",(0,a.yg)("inlineCode",{parentName:"li"},'FunctionRequiresIntegerValue("SLICE")'),".")))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/d4251823.1b779bc7.js b/docs/0.16.0/assets/js/d4251823.1b779bc7.js new file mode 100644 index 00000000..780cb661 --- /dev/null +++ b/docs/0.16.0/assets/js/d4251823.1b779bc7.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[1274],{5680:(e,t,n)=>{n.d(t,{xA:()=>u,yg:()=>y});var r=n(6540);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function s(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function a(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?s(Object(n),!0).forEach((function(t){i(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):s(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function o(e,t){if(null==e)return{};var n,r,i=function(e,t){if(null==e)return{};var n,r,i={},s=Object.keys(e);for(r=0;r<s.length;r++)n=s[r],t.indexOf(n)>=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(r=0;r<s.length;r++)n=s[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var l=r.createContext({}),p=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},u=function(e){var t=p(e.components);return r.createElement(l.Provider,{value:t},e.children)},c="mdxType",g={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},f=r.forwardRef((function(e,t){var n=e.components,i=e.mdxType,s=e.originalType,l=e.parentName,u=o(e,["components","mdxType","originalType","parentName"]),c=p(n),f=i,y=c["".concat(l,".").concat(f)]||c[f]||g[f]||s;return n?r.createElement(y,a(a({ref:t},u),{},{components:n})):r.createElement(y,a({ref:t},u))}));function y(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var s=n.length,a=new Array(s);a[0]=f;var o={};for(var l in t)hasOwnProperty.call(t,l)&&(o[l]=t[l]);o.originalType=e,o[c]="string"==typeof e?e:i,a[1]=o;for(var p=2;p<s;p++)a[p]=n[p];return r.createElement.apply(null,a)}return r.createElement.apply(null,n)}f.displayName="MDXCreateElement"},2152:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>a,default:()=>g,frontMatter:()=>s,metadata:()=>o,toc:()=>p});var r=n(8168),i=(n(6540),n(5680));const s={},a="FIND_IDX",o={unversionedId:"sql-syntax/functions/text/find-idx",id:"sql-syntax/functions/text/find-idx",title:"FIND_IDX",description:"The FIND_IDX function in SQL is used to return the position of the first occurrence of a substring in a string, optionally after a specified position.",source:"@site/docs/sql-syntax/functions/text/find-idx.md",sourceDirName:"sql-syntax/functions/text",slug:"/sql-syntax/functions/text/find-idx",permalink:"/docs/0.16.0/sql-syntax/functions/text/find-idx",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"CONCAT",permalink:"/docs/0.16.0/sql-syntax/functions/text/concat"},next:{title:"INITCAP",permalink:"/docs/0.16.0/sql-syntax/functions/text/initcap"}},l={},p=[{value:"Syntax",id:"syntax",level:2},{value:"Parameters",id:"parameters",level:2},{value:"Examples",id:"examples",level:2}],u={toc:p},c="wrapper";function g(e){let{components:t,...n}=e;return(0,i.yg)(c,(0,r.A)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,i.yg)("h1",{id:"find_idx"},"FIND_IDX"),(0,i.yg)("p",null,"The ",(0,i.yg)("inlineCode",{parentName:"p"},"FIND_IDX")," function in SQL is used to return the position of the first occurrence of a substring in a string, optionally after a specified position."),(0,i.yg)("h2",{id:"syntax"},"Syntax"),(0,i.yg)("p",null,"The syntax for the ",(0,i.yg)("inlineCode",{parentName:"p"},"FIND_IDX")," function in SQL is:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-sql"},"FIND_IDX ( string, substring, [ start_position ] )\n")),(0,i.yg)("h2",{id:"parameters"},"Parameters"),(0,i.yg)("ul",null,(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("inlineCode",{parentName:"li"},"string"),": The string where the search will take place."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("inlineCode",{parentName:"li"},"substring"),": The substring to find."),(0,i.yg)("li",{parentName:"ul"},(0,i.yg)("inlineCode",{parentName:"li"},"start_position")," (optional): The position at which to start the search. The first position in the string is 0. If the ",(0,i.yg)("inlineCode",{parentName:"li"},"start_position")," is not specified, the search starts from the beginning of the string.")),(0,i.yg)("h2",{id:"examples"},"Examples"),(0,i.yg)("p",null,"Let's consider a few examples to understand how to use the ",(0,i.yg)("inlineCode",{parentName:"p"},"FIND_IDX")," function."),(0,i.yg)("p",null,"Find the position of 'rg' in 'pork':"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT FIND_IDX('pork', 'rg') AS test;\n")),(0,i.yg)("p",null,"This will return 0, as 'rg' is not found in 'pork'."),(0,i.yg)("p",null,"Find the position of 'rg' in 'burger':"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT FIND_IDX('burger', 'rg') AS test;\n")),(0,i.yg)("p",null,"This will return 3, as the first occurrence of 'rg' in 'burger' is at position 3."),(0,i.yg)("p",null,"Find the position of 'r' in 'pork', starting from position 4:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT FIND_IDX('pork', 'r', 4) AS test;\n")),(0,i.yg)("p",null,"This will return 0, as 'r' is not found in 'pork' after position 4."),(0,i.yg)("p",null,"Find the position of 'r' in 'burger', starting from position 4:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT FIND_IDX('burger', 'r', 4) AS test;\n")),(0,i.yg)("p",null,"This will return 6, as the first occurrence of 'r' in 'burger' after position 4 is at position 6."),(0,i.yg)("p",null,"Find the position of an empty string in 'cheese':"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT FIND_IDX('cheese', '') AS test;\n")),(0,i.yg)("p",null,"This will return 0, because the search starts at the first position by default and the empty string is considered to be found at the start of any string."),(0,i.yg)("p",null,"Find the position of 's' in 'cheese':"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT FIND_IDX('cheese', 's') AS test;\n")),(0,i.yg)("p",null,"This will return 5, as the first occurrence of 's' in 'cheese' is at position 5."),(0,i.yg)("p",null,"Find the position of 'e' in 'cheese burger', starting from position 5:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT FIND_IDX('cheese burger', 'e', 5) AS test;\n")),(0,i.yg)("p",null,"This will return 6, because the search starts from position 5 and the next 'e' is at position 6."),(0,i.yg)("p",null,"Using a NULL value as the substring will return NULL:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT FIND_IDX('cheese', NULL) AS test;\n")))}g.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/d5aa49f9.6dad4890.js b/docs/0.16.0/assets/js/d5aa49f9.6dad4890.js new file mode 100644 index 00000000..f46ae09a --- /dev/null +++ b/docs/0.16.0/assets/js/d5aa49f9.6dad4890.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[3274],{5680:(e,t,r)=>{r.d(t,{xA:()=>l,yg:()=>y});var n=r(6540);function i(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function a(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?o(Object(r),!0).forEach((function(t){i(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):o(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function u(e,t){if(null==e)return{};var r,n,i=function(e,t){if(null==e)return{};var r,n,i={},o=Object.keys(e);for(n=0;n<o.length;n++)r=o[n],t.indexOf(r)>=0||(i[r]=e[r]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n<o.length;n++)r=o[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(i[r]=e[r])}return i}var c=n.createContext({}),s=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},l=function(e){var t=s(e.components);return n.createElement(c.Provider,{value:t},e.children)},p="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,i=e.mdxType,o=e.originalType,c=e.parentName,l=u(e,["components","mdxType","originalType","parentName"]),p=s(r),d=i,y=p["".concat(c,".").concat(d)]||p[d]||f[d]||o;return r?n.createElement(y,a(a({ref:t},l),{},{components:r})):n.createElement(y,a({ref:t},l))}));function y(e,t){var r=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=r.length,a=new Array(o);a[0]=d;var u={};for(var c in t)hasOwnProperty.call(t,c)&&(u[c]=t[c]);u.originalType=e,u[p]="string"==typeof e?e:i,a[1]=u;for(var s=2;s<o;s++)a[s]=r[s];return n.createElement.apply(null,a)}return n.createElement.apply(null,r)}d.displayName="MDXCreateElement"},776:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>f,frontMatter:()=>o,metadata:()=>u,toc:()=>s});var n=r(8168),i=(r(6540),r(5680));const o={},a="Unique Identifier",u={unversionedId:"ast-builder/functions/others/unique-identifier",id:"ast-builder/functions/others/unique-identifier",title:"Unique Identifier",description:"Todo",source:"@site/docs/ast-builder/functions/others/unique-identifier.md",sourceDirName:"ast-builder/functions/others",slug:"/ast-builder/functions/others/unique-identifier",permalink:"/docs/0.16.0/ast-builder/functions/others/unique-identifier",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"Type Conversion",permalink:"/docs/0.16.0/ast-builder/functions/others/type-conversion"},next:{title:"Introduction",permalink:"/docs/0.16.0/storages/intro"}},c={},s=[{value:"Todo",id:"todo",level:2}],l={toc:s},p="wrapper";function f(e){let{components:t,...r}=e;return(0,i.yg)(p,(0,n.A)({},l,r,{components:t,mdxType:"MDXLayout"}),(0,i.yg)("h1",{id:"unique-identifier"},"Unique Identifier"),(0,i.yg)("h2",{id:"todo"},"Todo"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre"},"- GENERATE_UUID: Generates a universally unique identifier (UUID).\n")))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/d7a493e6.f2613a57.js b/docs/0.16.0/assets/js/d7a493e6.f2613a57.js new file mode 100644 index 00000000..c416395e --- /dev/null +++ b/docs/0.16.0/assets/js/d7a493e6.f2613a57.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[5666],{5680:(e,n,t)=>{t.d(n,{xA:()=>p,yg:()=>g});var r=t(6540);function a(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function o(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function i(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?o(Object(t),!0).forEach((function(n){a(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):o(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function c(e,n){if(null==e)return{};var t,r,a=function(e,n){if(null==e)return{};var t,r,a={},o=Object.keys(e);for(r=0;r<o.length;r++)t=o[r],n.indexOf(t)>=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r<o.length;r++)t=o[r],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var l=r.createContext({}),s=function(e){var n=r.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},p=function(e){var n=s(e.components);return r.createElement(l.Provider,{value:n},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},m=r.forwardRef((function(e,n){var t=e.components,a=e.mdxType,o=e.originalType,l=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),u=s(t),m=a,g=u["".concat(l,".").concat(m)]||u[m]||d[m]||o;return t?r.createElement(g,i(i({ref:n},p),{},{components:t})):r.createElement(g,i({ref:n},p))}));function g(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var o=t.length,i=new Array(o);i[0]=m;var c={};for(var l in n)hasOwnProperty.call(n,l)&&(c[l]=n[l]);c.originalType=e,c[u]="string"==typeof e?e:a,i[1]=c;for(var s=2;s<o;s++)i[s]=t[s];return r.createElement.apply(null,i)}return r.createElement.apply(null,t)}m.displayName="MDXCreateElement"},318:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>i,default:()=>d,frontMatter:()=>o,metadata:()=>c,toc:()=>s});var r=t(8168),a=(t(6540),t(5680));const o={},i="Case Conversion",c={unversionedId:"ast-builder/functions/text/case-conversion",id:"ast-builder/functions/text/case-conversion",title:"Case Conversion",description:"GlueSQL provides several text case conversion functions that allow you to convert text data to upper case, lower case or capitalize each word in a string.",source:"@site/docs/ast-builder/functions/text/case-conversion.md",sourceDirName:"ast-builder/functions/text",slug:"/ast-builder/functions/text/case-conversion",permalink:"/docs/0.16.0/ast-builder/functions/text/case-conversion",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"Value Checking",permalink:"/docs/0.16.0/ast-builder/expressions/value-checking"},next:{title:"Character Conversion",permalink:"/docs/0.16.0/ast-builder/functions/text/character-conversion"}},l={},s=[{value:"Upper Case Conversion - upper",id:"upper-case-conversion---upper",level:2},{value:"Lower Case Conversion - lower",id:"lower-case-conversion---lower",level:2},{value:"Initial Capital Case Conversion - initcap",id:"initial-capital-case-conversion---initcap",level:2}],p={toc:s},u="wrapper";function d(e){let{components:n,...t}=e;return(0,a.yg)(u,(0,r.A)({},p,t,{components:n,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"case-conversion"},"Case Conversion"),(0,a.yg)("p",null,"GlueSQL provides several text case conversion functions that allow you to convert text data to upper case, lower case or capitalize each word in a string."),(0,a.yg)("p",null,"For this tutorial, we assume there's a table named ",(0,a.yg)("inlineCode",{parentName:"p"},"Item")," with various columns including ",(0,a.yg)("inlineCode",{parentName:"p"},"name"),", ",(0,a.yg)("inlineCode",{parentName:"p"},"opt_name"),", and ",(0,a.yg)("inlineCode",{parentName:"p"},"capped_name")," which are of ",(0,a.yg)("inlineCode",{parentName:"p"},"TEXT")," type."),(0,a.yg)("h2",{id:"upper-case-conversion---upper"},"Upper Case Conversion - upper"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"upper")," function converts a text string to upper case."),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Item")\n .select()\n .project(col("name").upper()) // Convert the \'name\' column to upper case\n .execute(glue)\n .await;\n')),(0,a.yg)("h2",{id:"lower-case-conversion---lower"},"Lower Case Conversion - lower"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"lower")," function converts a text string to lower case."),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Item")\n .select()\n .project(col("name").lower()) // Convert the \'name\' column to lower case\n .execute(glue)\n .await;\n')),(0,a.yg)("p",null,"You can also filter the records based on the lower case conversion:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Item")\n .select()\n .filter(col("name").lower().eq("\'abcd\'")) // Filter records where lower case of \'name\' is \'abcd\'\n .project("name")\n .project(lower("name"))\n .execute(glue)\n .await;\n')),(0,a.yg)("h2",{id:"initial-capital-case-conversion---initcap"},"Initial Capital Case Conversion - initcap"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"initcap")," function converts a text string to initial capital case, i.e., it capitalizes the first character of each word in the string."),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Item")\n .select()\n .project(col("capped_name").initcap()) // Convert the \'capped_name\' column to initial capital case\n .execute(glue)\n .await;\n')),(0,a.yg)("p",null,"You can also filter the records based on the initial capital case conversion:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Item")\n .select()\n .filter(col("capped_name").initcap().eq("\'H/I Jk\'")) // Filter records where initial capital case of \'capped_name\' is \'H/I Jk\'\n .project("capped_name")\n .execute(glue)\n .await;\n')))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/d8746e52.e4d0dc41.js b/docs/0.16.0/assets/js/d8746e52.e4d0dc41.js new file mode 100644 index 00000000..4573d5ab --- /dev/null +++ b/docs/0.16.0/assets/js/d8746e52.e4d0dc41.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[5e3],{5680:(e,t,n)=>{n.d(t,{xA:()=>p,yg:()=>y});var r=n(6540);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function l(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function o(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},i=Object.keys(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),u=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},p=function(e){var t=u(e.components);return r.createElement(s.Provider,{value:t},e.children)},c="mdxType",g={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,s=e.parentName,p=o(e,["components","mdxType","originalType","parentName"]),c=u(n),m=a,y=c["".concat(s,".").concat(m)]||c[m]||g[m]||i;return n?r.createElement(y,l(l({ref:t},p),{},{components:n})):r.createElement(y,l({ref:t},p))}));function y(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,l=new Array(i);l[0]=m;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[c]="string"==typeof e?e:a,l[1]=o;for(var u=2;u<i;u++)l[u]=n[u];return r.createElement.apply(null,l)}return r.createElement.apply(null,n)}m.displayName="MDXCreateElement"},2248:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>g,frontMatter:()=>i,metadata:()=>o,toc:()=>u});var r=n(8168),a=(n(6540),n(5680));const i={},l="SUBSTR",o={unversionedId:"sql-syntax/functions/text/substr",id:"sql-syntax/functions/text/substr",title:"SUBSTR",description:"The SUBSTR function in SQL is used to extract a substring from a string.",source:"@site/docs/sql-syntax/functions/text/substr.md",sourceDirName:"sql-syntax/functions/text",slug:"/sql-syntax/functions/text/substr",permalink:"/docs/0.16.0/sql-syntax/functions/text/substr",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"RTRIM",permalink:"/docs/0.16.0/sql-syntax/functions/text/rtrim"},next:{title:"TRIM",permalink:"/docs/0.16.0/sql-syntax/functions/text/trim"}},s={},u=[{value:"Syntax",id:"syntax",level:2},{value:"Parameters",id:"parameters",level:2},{value:"Return Value",id:"return-value",level:2},{value:"Errors",id:"errors",level:2},{value:"Examples",id:"examples",level:2}],p={toc:u},c="wrapper";function g(e){let{components:t,...n}=e;return(0,a.yg)(c,(0,r.A)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"substr"},"SUBSTR"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"SUBSTR")," function in SQL is used to extract a substring from a string."),(0,a.yg)("h2",{id:"syntax"},"Syntax"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SUBSTR(string, start_position, length)\n")),(0,a.yg)("h2",{id:"parameters"},"Parameters"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"string"),": The original string."),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"start_position"),": The position in the string where the extraction of the substring will begin. The position of the first character is 1. If ",(0,a.yg)("inlineCode",{parentName:"li"},"start_position")," is 0 or negative, the function treats it as 1."),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"length")," (optional): The number of characters to extract. If ",(0,a.yg)("inlineCode",{parentName:"li"},"length")," is not included, the function will return all characters starting from ",(0,a.yg)("inlineCode",{parentName:"li"},"start_position"),".")),(0,a.yg)("h2",{id:"return-value"},"Return Value"),(0,a.yg)("p",null,"The function returns a string which is a substring of the original string. The substring starts at ",(0,a.yg)("inlineCode",{parentName:"p"},"start_position")," and has ",(0,a.yg)("inlineCode",{parentName:"p"},"length")," number of characters."),(0,a.yg)("h2",{id:"errors"},"Errors"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},"If the ",(0,a.yg)("inlineCode",{parentName:"li"},"string")," parameter is not a string value, a ",(0,a.yg)("inlineCode",{parentName:"li"},"EvaluateError::FunctionRequiresStringValue")," error will be returned."),(0,a.yg)("li",{parentName:"ul"},"If the ",(0,a.yg)("inlineCode",{parentName:"li"},"start_position")," or ",(0,a.yg)("inlineCode",{parentName:"li"},"length")," parameters are not integer values, a ",(0,a.yg)("inlineCode",{parentName:"li"},"EvaluateError::FunctionRequiresIntegerValue")," error will be returned."),(0,a.yg)("li",{parentName:"ul"},"If the ",(0,a.yg)("inlineCode",{parentName:"li"},"length")," parameter is negative, a ",(0,a.yg)("inlineCode",{parentName:"li"},"EvaluateError::NegativeSubstrLenNotAllowed")," error will be returned.")),(0,a.yg)("h2",{id:"examples"},"Examples"),(0,a.yg)("p",null,"Consider a table ",(0,a.yg)("inlineCode",{parentName:"p"},"Item")," created and filled with the following data:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE Item (name TEXT);\nINSERT INTO Item VALUES ('Blop mc blee'), ('B'), ('Steven the &long named$ folken!');\n")),(0,a.yg)("p",null,"You can use the ",(0,a.yg)("inlineCode",{parentName:"p"},"SUBSTR")," function to get a substring from the ",(0,a.yg)("inlineCode",{parentName:"p"},"name")," values:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT SUBSTR(name, 2) AS test FROM Item;\n")),(0,a.yg)("p",null,"This will return:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre"},"lop mc blee\n(empty string)\nteven the &long named$ folken!\n")),(0,a.yg)("p",null,"The function takes the substring starting from the second character until the end for each ",(0,a.yg)("inlineCode",{parentName:"p"},"name")," value."))}g.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/d941076d.e217ef5e.js b/docs/0.16.0/assets/js/d941076d.e217ef5e.js new file mode 100644 index 00000000..af866446 --- /dev/null +++ b/docs/0.16.0/assets/js/d941076d.e217ef5e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[262],{5680:(e,t,n)=>{n.d(t,{xA:()=>p,yg:()=>g});var r=n(6540);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?a(Object(n),!0).forEach((function(t){o(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):a(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},a=Object.keys(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var l=r.createContext({}),d=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=d(e.components);return r.createElement(l.Provider,{value:t},e.children)},u="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=d(n),m=o,g=u["".concat(l,".").concat(m)]||u[m]||c[m]||a;return n?r.createElement(g,i(i({ref:t},p),{},{components:n})):r.createElement(g,i({ref:t},p))}));function g(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,i=new Array(a);i[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[u]="string"==typeof e?e:o,i[1]=s;for(var d=2;d<a;d++)i[d]=n[d];return r.createElement.apply(null,i)}return r.createElement.apply(null,n)}m.displayName="MDXCreateElement"},6078:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>c,frontMatter:()=>a,metadata:()=>s,toc:()=>d});var r=n(8168),o=(n(6540),n(5680));const a={sidebar_position:7},i="Index",s={unversionedId:"storages/developing-custom-storages/store-traits/index-trait",id:"storages/developing-custom-storages/store-traits/index-trait",title:"Index",description:"The Index trait is designed to support non-clustered indexes. If you only need to support pre-built non-clustered indexes, implementing the Index trait without the IndexMut trait is sufficient. Note that clustered indexes (PRIMARY KEY) are automatically supported by the Store & StoreMut implementations. The Index trait is specifically for non-clustered index support.",source:"@site/docs/storages/developing-custom-storages/store-traits/index-trait.md",sourceDirName:"storages/developing-custom-storages/store-traits",slug:"/storages/developing-custom-storages/store-traits/index-trait",permalink:"/docs/0.16.0/storages/developing-custom-storages/store-traits/index-trait",draft:!1,tags:[],version:"current",sidebarPosition:7,frontMatter:{sidebar_position:7},sidebar:"autoSidebar",previous:{title:"CustomFunctionMut",permalink:"/docs/0.16.0/storages/developing-custom-storages/store-traits/custom-function-mut"},next:{title:"IndexMut",permalink:"/docs/0.16.0/storages/developing-custom-storages/store-traits/index-mut"}},l={},d=[],p={toc:d},u="wrapper";function c(e){let{components:t,...n}=e;return(0,o.yg)(u,(0,r.A)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,o.yg)("h1",{id:"index"},"Index"),(0,o.yg)("p",null,"The ",(0,o.yg)("inlineCode",{parentName:"p"},"Index")," trait is designed to support non-clustered indexes. If you only need to support pre-built non-clustered indexes, implementing the ",(0,o.yg)("inlineCode",{parentName:"p"},"Index")," trait without the ",(0,o.yg)("inlineCode",{parentName:"p"},"IndexMut")," trait is sufficient. Note that clustered indexes (PRIMARY KEY) are automatically supported by the ",(0,o.yg)("inlineCode",{parentName:"p"},"Store")," & ",(0,o.yg)("inlineCode",{parentName:"p"},"StoreMut")," implementations. The ",(0,o.yg)("inlineCode",{parentName:"p"},"Index")," trait is specifically for non-clustered index support."),(0,o.yg)("p",null,"Currently, GlueSQL's query planner only supports a logical planner, so the performance of finding non-clustered indexes is not optimal yet, but it is being improved. If you want to use non-clustered indexes more precisely, using the AST Builder to directly specify the index you want to use can be a good approach."),(0,o.yg)("p",null,"A brief explanation of non-clustered and clustered indexes:"),(0,o.yg)("ul",null,(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("p",{parentName:"li"},"Non-clustered index: A non-clustered index is an index that doesn't affect the physical ordering of the data rows in the table. Instead, it maintains a separate data structure that contains a reference to the actual data rows, allowing for faster search operations without rearranging the data itself.")),(0,o.yg)("li",{parentName:"ul"},(0,o.yg)("p",{parentName:"li"},"Clustered index: A clustered index determines the physical order of the data in the table. In other words, the data rows are stored on disk in the same order as the index. There can be only one clustered index per table, which is usually defined by the PRIMARY KEY constraint."))),(0,o.yg)("p",null,"There is one method to implement for the ",(0,o.yg)("inlineCode",{parentName:"p"},"Index")," trait:"),(0,o.yg)("ol",null,(0,o.yg)("li",{parentName:"ol"},(0,o.yg)("inlineCode",{parentName:"li"},"scan_indexed_data"),": This method retrieves indexed data from the storage system using the provided table name, index name, sorting order, and comparison value.")),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-rust"},"#[async_trait(?Send)]\npub trait Index {\n async fn scan_indexed_data(\n &self,\n _table_name: &str,\n _index_name: &str,\n _asc: Option<bool>,\n _cmp_value: Option<(&IndexOperator, Value)>,\n ) -> Result<RowIter>;\n}\n")))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/d97b7d4d.9b38cbbf.js b/docs/0.16.0/assets/js/d97b7d4d.9b38cbbf.js new file mode 100644 index 00000000..819e4fb9 --- /dev/null +++ b/docs/0.16.0/assets/js/d97b7d4d.9b38cbbf.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[3352],{5680:(e,t,a)=>{a.d(t,{xA:()=>c,yg:()=>y});var n=a(6540);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function o(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function i(e){for(var t=1;t<arguments.length;t++){var a=null!=arguments[t]?arguments[t]:{};t%2?o(Object(a),!0).forEach((function(t){r(e,t,a[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(a)):o(Object(a)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(a,t))}))}return e}function l(e,t){if(null==e)return{};var a,n,r=function(e,t){if(null==e)return{};var a,n,r={},o=Object.keys(e);for(n=0;n<o.length;n++)a=o[n],t.indexOf(a)>=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n<o.length;n++)a=o[n],t.indexOf(a)>=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var s=n.createContext({}),u=function(e){var t=n.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},c=function(e){var t=u(e.components);return n.createElement(s.Provider,{value:t},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},g=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,o=e.originalType,s=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),d=u(a),g=r,y=d["".concat(s,".").concat(g)]||d[g]||p[g]||o;return a?n.createElement(y,i(i({ref:t},c),{},{components:a})):n.createElement(y,i({ref:t},c))}));function y(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=a.length,i=new Array(o);i[0]=g;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[d]="string"==typeof e?e:r,i[1]=l;for(var u=2;u<o;u++)i[u]=a[u];return n.createElement.apply(null,i)}return n.createElement.apply(null,a)}g.displayName="MDXCreateElement"},4351:(e,t,a)=>{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>p,frontMatter:()=>o,metadata:()=>l,toc:()=>u});var n=a(8168),r=(a(6540),a(5680));const o={sidebar_position:2},i="Using Preloaded Data",l={unversionedId:"ast-builder/statements/querying/using-preloaded-data",id:"ast-builder/statements/querying/using-preloaded-data",title:"Using Preloaded Data",description:"This guide will show you how to use AST Builder to query data that has already been loaded into memory, as opposed to querying data from storage. This is similar to SQL's VALUES functionality.",source:"@site/docs/ast-builder/statements/querying/using-preloaded-data.md",sourceDirName:"ast-builder/statements/querying",slug:"/ast-builder/statements/querying/using-preloaded-data",permalink:"/docs/0.16.0/ast-builder/statements/querying/using-preloaded-data",draft:!1,tags:[],version:"current",sidebarPosition:2,frontMatter:{sidebar_position:2},sidebar:"autoSidebar",previous:{title:"Fetching Data from Storage",permalink:"/docs/0.16.0/ast-builder/statements/querying/fetching-data-from-storage"},next:{title:"Creating Derived Subqueries",permalink:"/docs/0.16.0/ast-builder/statements/querying/creating-derived-subqueries"}},s={},u=[{value:"Creating a Values Object",id:"creating-a-values-object",level:2},{value:"Sorting Results (ORDER BY)",id:"sorting-results-order-by",level:2},{value:"Pagination (OFFSET, LIMIT)",id:"pagination-offset-limit",level:2},{value:"Querying Preloaded Data",id:"querying-preloaded-data",level:2}],c={toc:u},d="wrapper";function p(e){let{components:t,...a}=e;return(0,r.yg)(d,(0,n.A)({},c,a,{components:t,mdxType:"MDXLayout"}),(0,r.yg)("h1",{id:"using-preloaded-data"},"Using Preloaded Data"),(0,r.yg)("p",null,"This guide will show you how to use AST Builder to query data that has already been loaded into memory, as opposed to querying data from storage. This is similar to SQL's ",(0,r.yg)("inlineCode",{parentName:"p"},"VALUES")," functionality. "),(0,r.yg)("h2",{id:"creating-a-values-object"},"Creating a Values Object"),(0,r.yg)("p",null,"To create a ",(0,r.yg)("inlineCode",{parentName:"p"},"values()")," object, you can either provide a vector of strings or a vector of vectors of strings. Each inner vector represents a row of data, and each string within the inner vector represents a value in that row."),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-rust"},'use gluesql_core::ast_builder::values;\n\nlet actual = values(vec!["1, \'Glue\'", "2, \'SQL\'", "3, \'Rust\'"])\n .execute(glue)\n .await;\n\nlet actual = values(vec![\n vec!["1", "\'Glue\'"],\n vec!["2", "\'SQL\'"],\n vec!["3", "\'Rust\'"],\n])\n.execute(glue)\n.await;\n')),(0,r.yg)("h2",{id:"sorting-results-order-by"},"Sorting Results (ORDER BY)"),(0,r.yg)("p",null,"To sort the results of a ",(0,r.yg)("inlineCode",{parentName:"p"},"values()")," query, use the ",(0,r.yg)("inlineCode",{parentName:"p"},"order_by()")," method."),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = values(vec!["1, \'Glue\'", "2, \'SQL\'", "3, \'Rust\'"])\n .order_by("column2 desc")\n .execute(glue)\n .await;\n')),(0,r.yg)("h2",{id:"pagination-offset-limit"},"Pagination (OFFSET, LIMIT)"),(0,r.yg)("p",null,"You can paginate the results of a ",(0,r.yg)("inlineCode",{parentName:"p"},"values()")," query using the ",(0,r.yg)("inlineCode",{parentName:"p"},"offset()")," and ",(0,r.yg)("inlineCode",{parentName:"p"},"limit()")," methods."),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-rust"},"let actual = values(vec![\"1, 'Glue'\", \"2, 'SQL'\", \"3, 'Rust'\"])\n .offset(1)\n .execute(glue)\n .await;\n\nlet actual = values(vec![\"1, 'Glue'\", \"2, 'SQL'\", \"3, 'Rust'\"])\n .limit(2)\n .execute(glue)\n .await;\n")),(0,r.yg)("h2",{id:"querying-preloaded-data"},"Querying Preloaded Data"),(0,r.yg)("p",null,"To query preloaded data using the ",(0,r.yg)("inlineCode",{parentName:"p"},"values()")," object, you can call the ",(0,r.yg)("inlineCode",{parentName:"p"},"select()")," method, and then use the ",(0,r.yg)("inlineCode",{parentName:"p"},"project()")," method to specify the columns you want to include in the result."),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = values(vec!["1, \'Glue\'", "2, \'SQL\'", "3, \'Rust\'"])\n .alias_as("Sub")\n .select()\n .project("column1 AS id")\n .project("column2 AS name")\n .execute(glue)\n .await;\n')))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/dafe2799.0365f5ae.js b/docs/0.16.0/assets/js/dafe2799.0365f5ae.js new file mode 100644 index 00000000..fda775ea --- /dev/null +++ b/docs/0.16.0/assets/js/dafe2799.0365f5ae.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[1202],{5680:(e,t,n)=>{n.d(t,{xA:()=>c,yg:()=>m});var r=n(6540);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function l(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function o(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},i=Object.keys(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),u=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},c=function(e){var t=u(e.components);return r.createElement(s.Provider,{value:t},e.children)},p="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},g=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,s=e.parentName,c=o(e,["components","mdxType","originalType","parentName"]),p=u(n),g=a,m=p["".concat(s,".").concat(g)]||p[g]||f[g]||i;return n?r.createElement(m,l(l({ref:t},c),{},{components:n})):r.createElement(m,l({ref:t},c))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,l=new Array(i);l[0]=g;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[p]="string"==typeof e?e:a,l[1]=o;for(var u=2;u<i;u++)l[u]=n[u];return r.createElement.apply(null,l)}return r.createElement.apply(null,n)}g.displayName="MDXCreateElement"},9324:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>f,frontMatter:()=>i,metadata:()=>o,toc:()=>u});var r=n(8168),a=(n(6540),n(5680));const i={},l="LEFT",o={unversionedId:"sql-syntax/functions/text/left",id:"sql-syntax/functions/text/left",title:"LEFT",description:"The LEFT function in SQL returns the specified number of characters from the start (left side) of a given string.",source:"@site/docs/sql-syntax/functions/text/left.md",sourceDirName:"sql-syntax/functions/text",slug:"/sql-syntax/functions/text/left",permalink:"/docs/0.16.0/sql-syntax/functions/text/left",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"INITCAP",permalink:"/docs/0.16.0/sql-syntax/functions/text/initcap"},next:{title:"LOWER",permalink:"/docs/0.16.0/sql-syntax/functions/text/lower"}},s={},u=[{value:"Syntax",id:"syntax",level:2},{value:"Parameters",id:"parameters",level:2},{value:"Return Value",id:"return-value",level:2},{value:"Errors",id:"errors",level:2},{value:"Examples",id:"examples",level:2}],c={toc:u},p="wrapper";function f(e){let{components:t,...n}=e;return(0,a.yg)(p,(0,r.A)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"left"},"LEFT"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"LEFT")," function in SQL returns the specified number of characters from the start (left side) of a given string."),(0,a.yg)("h2",{id:"syntax"},"Syntax"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"LEFT(string, number)\n")),(0,a.yg)("h2",{id:"parameters"},"Parameters"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"string"),": The original string from which to extract characters."),(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"number"),": The number of characters to extract from the start of the string. This must be an integer.")),(0,a.yg)("h2",{id:"return-value"},"Return Value"),(0,a.yg)("p",null,"The function returns a string, which consists of the specified number of characters from the start of the original string. If the original string is shorter than the specified number, the function returns the whole string."),(0,a.yg)("h2",{id:"errors"},"Errors"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},"If the ",(0,a.yg)("inlineCode",{parentName:"li"},"number")," argument is not an integer, a ",(0,a.yg)("inlineCode",{parentName:"li"},"FunctionRequiresIntegerValue")," error will be returned."),(0,a.yg)("li",{parentName:"ul"},"If the ",(0,a.yg)("inlineCode",{parentName:"li"},"string")," argument is not a string, a ",(0,a.yg)("inlineCode",{parentName:"li"},"FunctionRequiresStringValue")," error will be returned.")),(0,a.yg)("h2",{id:"examples"},"Examples"),(0,a.yg)("p",null,"Consider a table ",(0,a.yg)("inlineCode",{parentName:"p"},"Item")," created and filled with the following data:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE Item (\n name TEXT DEFAULT LEFT('abc', 1)\n);\nINSERT INTO Item VALUES ('Blop mc blee'), ('B'), ('Steven the &long named$ folken!');\n")),(0,a.yg)("p",null,"You can use the ",(0,a.yg)("inlineCode",{parentName:"p"},"LEFT")," function to extract the first three characters of each ",(0,a.yg)("inlineCode",{parentName:"p"},"name"),":"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT LEFT(name, 3) AS test FROM Item;\n")),(0,a.yg)("p",null,"This will return:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre"},"Blo\nB\nSte\n")),(0,a.yg)("p",null,"Note that when the string length is less than the specified number (as with 'B'), the function will return the whole string."))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/db0d9cb2.c1e2f54b.js b/docs/0.16.0/assets/js/db0d9cb2.c1e2f54b.js new file mode 100644 index 00000000..5c8930bc --- /dev/null +++ b/docs/0.16.0/assets/js/db0d9cb2.c1e2f54b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[129],{5680:(e,t,n)=>{n.d(t,{xA:()=>u,yg:()=>g});var r=n(6540);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function l(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function i(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},o=Object.keys(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),c=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},u=function(e){var t=c(e.components);return r.createElement(s.Provider,{value:t},e.children)},p="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),p=c(n),m=a,g=p["".concat(s,".").concat(m)]||p[m]||f[m]||o;return n?r.createElement(g,l(l({ref:t},u),{},{components:n})):r.createElement(g,l({ref:t},u))}));function g(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,l=new Array(o);l[0]=m;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i[p]="string"==typeof e?e:a,l[1]=i;for(var c=2;c<o;c++)l[c]=n[c];return r.createElement.apply(null,l)}return r.createElement.apply(null,n)}m.displayName="MDXCreateElement"},394:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>f,frontMatter:()=>o,metadata:()=>i,toc:()=>c});var r=n(8168),a=(n(6540),n(5680));const o={},l="LOG",i={unversionedId:"sql-syntax/functions/math/log",id:"sql-syntax/functions/math/log",title:"LOG",description:"The LOG function calculates the logarithm of a number with a specified base. It takes two FLOAT or INTEGER arguments and returns a FLOAT value representing the logarithm of the first argument with the base specified by the second argument.",source:"@site/docs/sql-syntax/functions/math/log.md",sourceDirName:"sql-syntax/functions/math",slug:"/sql-syntax/functions/math/log",permalink:"/docs/0.16.0/sql-syntax/functions/math/log",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"LN",permalink:"/docs/0.16.0/sql-syntax/functions/math/ln"},next:{title:"LOG10",permalink:"/docs/0.16.0/sql-syntax/functions/math/log10"}},s={},c=[{value:"Example",id:"example",level:2},{value:"Errors",id:"errors",level:2}],u={toc:c},p="wrapper";function f(e){let{components:t,...n}=e;return(0,a.yg)(p,(0,r.A)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"log"},"LOG"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"LOG")," function calculates the logarithm of a number with a specified base. It takes two FLOAT or INTEGER arguments and returns a FLOAT value representing the logarithm of the first argument with the base specified by the second argument."),(0,a.yg)("h2",{id:"example"},"Example"),(0,a.yg)("p",null,"The following example demonstrates the usage of the ",(0,a.yg)("inlineCode",{parentName:"p"},"LOG")," function in a SQL query:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE SingleItem (id INTEGER DEFAULT LOG(2, 64));\n\nINSERT INTO SingleItem VALUES (0);\n\nSELECT\n LOG(64.0, 2.0) as log_1,\n LOG(0.04, 10.0) as log_2\nFROM SingleItem;\n")),(0,a.yg)("p",null,"This will return the following result:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre"},"log_1 | log_2\n------+-------------------\n6.0 | -1.39794\n")),(0,a.yg)("h2",{id:"errors"},"Errors"),(0,a.yg)("ol",null,(0,a.yg)("li",{parentName:"ol"},"If either of the arguments is not of FLOAT or INTEGER type, a ",(0,a.yg)("inlineCode",{parentName:"li"},"FunctionRequiresFloatValue")," error will be raised."),(0,a.yg)("li",{parentName:"ol"},"If the number of arguments provided to the function is not equal to 2, a ",(0,a.yg)("inlineCode",{parentName:"li"},"FunctionArgsLengthNotMatching")," error will be raised.")))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/dc8f2f6c.1fb3dce7.js b/docs/0.16.0/assets/js/dc8f2f6c.1fb3dce7.js new file mode 100644 index 00000000..faa2b381 --- /dev/null +++ b/docs/0.16.0/assets/js/dc8f2f6c.1fb3dce7.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[2735],{5680:(e,t,n)=>{n.d(t,{xA:()=>y,yg:()=>m});var r=n(6540);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},i=Object.keys(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),p=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},y=function(e){var t=p(e.components);return r.createElement(s.Provider,{value:t},e.children)},u="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,s=e.parentName,y=l(e,["components","mdxType","originalType","parentName"]),u=p(n),d=a,m=u["".concat(s,".").concat(d)]||u[d]||c[d]||i;return n?r.createElement(m,o(o({ref:t},y),{},{components:n})):r.createElement(m,o({ref:t},y))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,o=new Array(i);o[0]=d;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[u]="string"==typeof e?e:a,o[1]=l;for(var p=2;p<i;p++)o[p]=n[p];return r.createElement.apply(null,o)}return r.createElement.apply(null,n)}d.displayName="MDXCreateElement"},2143:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>c,frontMatter:()=>i,metadata:()=>l,toc:()=>p});var r=n(8168),a=(n(6540),n(5680));const i={sidebar_position:2},o="JOIN",l={unversionedId:"sql-syntax/statements/querying/join",id:"sql-syntax/statements/querying/join",title:"JOIN",description:"GlueSQL supports two types of JOIN operations:",source:"@site/docs/sql-syntax/statements/querying/join.md",sourceDirName:"sql-syntax/statements/querying",slug:"/sql-syntax/statements/querying/join",permalink:"/docs/0.16.0/sql-syntax/statements/querying/join",draft:!1,tags:[],version:"current",sidebarPosition:2,frontMatter:{sidebar_position:2},sidebar:"autoSidebar",previous:{title:"WHERE",permalink:"/docs/0.16.0/sql-syntax/statements/querying/where"},next:{title:"LIMIT & OFFSET",permalink:"/docs/0.16.0/sql-syntax/statements/querying/limit"}},s={},p=[{value:"(INNER) JOIN",id:"inner-join",level:2},{value:"LEFT (OUTER) JOIN",id:"left-outer-join",level:2}],y={toc:p},u="wrapper";function c(e){let{components:t,...n}=e;return(0,a.yg)(u,(0,r.A)({},y,n,{components:t,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"join"},"JOIN"),(0,a.yg)("p",null,"GlueSQL supports two types of JOIN operations:"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},"(INNER) JOIN"),(0,a.yg)("li",{parentName:"ul"},"LEFT (OUTER) JOIN")),(0,a.yg)("p",null,"Please note that ",(0,a.yg)("inlineCode",{parentName:"p"},"FULL OUTER JOIN")," and ",(0,a.yg)("inlineCode",{parentName:"p"},"RIGHT JOIN")," are currently not supported."),(0,a.yg)("h2",{id:"inner-join"},"(INNER) JOIN"),(0,a.yg)("p",null,"An INNER JOIN combines rows from two tables based on a specified condition. Rows that do not satisfy the condition are excluded from the result."),(0,a.yg)("p",null,"Here's an example using the provided test code:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT * FROM Item INNER JOIN Player ON Player.id = Item.player_id WHERE Player.id = 1;\n")),(0,a.yg)("p",null,"This query retrieves all rows from the ",(0,a.yg)("inlineCode",{parentName:"p"},"Item")," and ",(0,a.yg)("inlineCode",{parentName:"p"},"Player")," tables where the ",(0,a.yg)("inlineCode",{parentName:"p"},"id")," in the ",(0,a.yg)("inlineCode",{parentName:"p"},"Player")," table matches the ",(0,a.yg)("inlineCode",{parentName:"p"},"player_id")," in the ",(0,a.yg)("inlineCode",{parentName:"p"},"Item")," table, and the ",(0,a.yg)("inlineCode",{parentName:"p"},"Player.id")," is equal to 1."),(0,a.yg)("h2",{id:"left-outer-join"},"LEFT (OUTER) JOIN"),(0,a.yg)("p",null,"A LEFT JOIN (also known as LEFT OUTER JOIN) combines rows from two tables based on a specified condition. For each row in the left table that does not have a matching row in the right table, the result will contain NULL values."),(0,a.yg)("p",null,"Here's an example using the provided test code:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT * FROM Item LEFT JOIN Player ON Player.id = Item.player_id WHERE quantity = 1;\n")),(0,a.yg)("p",null,"This query retrieves all rows from the ",(0,a.yg)("inlineCode",{parentName:"p"},"Item")," table and any matching rows from the ",(0,a.yg)("inlineCode",{parentName:"p"},"Player")," table where the ",(0,a.yg)("inlineCode",{parentName:"p"},"id")," in the ",(0,a.yg)("inlineCode",{parentName:"p"},"Player")," table matches the ",(0,a.yg)("inlineCode",{parentName:"p"},"player_id")," in the ",(0,a.yg)("inlineCode",{parentName:"p"},"Item")," table. If there's no match, NULL values are returned for the ",(0,a.yg)("inlineCode",{parentName:"p"},"Player")," table columns. The result is then filtered by the ",(0,a.yg)("inlineCode",{parentName:"p"},"quantity")," column in the ",(0,a.yg)("inlineCode",{parentName:"p"},"Item")," table with a value of 1."),(0,a.yg)("p",null,"Remember to replace the table names, column names, and data types as needed for your specific use case."))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/dd9db7c1.95fe8d2d.js b/docs/0.16.0/assets/js/dd9db7c1.95fe8d2d.js new file mode 100644 index 00000000..e205264f --- /dev/null +++ b/docs/0.16.0/assets/js/dd9db7c1.95fe8d2d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[3497],{581:e=>{e.exports=JSON.parse('{"label":"query-interface","permalink":"/docs/0.16.0/blog/tags/query-interface","allTagsPath":"/docs/0.16.0/blog/tags","count":1}')}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/df2eb7da.6039d156.js b/docs/0.16.0/assets/js/df2eb7da.6039d156.js new file mode 100644 index 00000000..f2d76dac --- /dev/null +++ b/docs/0.16.0/assets/js/df2eb7da.6039d156.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[1502],{5680:(e,n,t)=>{t.d(n,{xA:()=>p,yg:()=>y});var a=t(6540);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function i(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function l(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?i(Object(t),!0).forEach((function(n){r(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):i(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function o(e,n){if(null==e)return{};var t,a,r=function(e,n){if(null==e)return{};var t,a,r={},i=Object.keys(e);for(a=0;a<i.length;a++)t=i[a],n.indexOf(t)>=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a<i.length;a++)t=i[a],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var s=a.createContext({}),u=function(e){var n=a.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):l(l({},n),e)),t},p=function(e){var n=u(e.components);return a.createElement(s.Provider,{value:n},e.children)},m="mdxType",c={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},d=a.forwardRef((function(e,n){var t=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,p=o(e,["components","mdxType","originalType","parentName"]),m=u(t),d=r,y=m["".concat(s,".").concat(d)]||m[d]||c[d]||i;return t?a.createElement(y,l(l({ref:n},p),{},{components:t})):a.createElement(y,l({ref:n},p))}));function y(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var i=t.length,l=new Array(i);l[0]=d;var o={};for(var s in n)hasOwnProperty.call(n,s)&&(o[s]=n[s]);o.originalType=e,o[m]="string"==typeof e?e:r,l[1]=o;for(var u=2;u<i;u++)l[u]=t[u];return a.createElement.apply(null,l)}return a.createElement.apply(null,t)}d.displayName="MDXCreateElement"},498:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>s,contentTitle:()=>l,default:()=>c,frontMatter:()=>i,metadata:()=>o,toc:()=>u});var a=t(8168),r=(t(6540),t(5680));const i={sidebar_position:1},l="INSERT",o={unversionedId:"sql-syntax/statements/data-manipulation/insert",id:"sql-syntax/statements/data-manipulation/insert",title:"INSERT",description:"The INSERT statement is used to insert new records into a table. You can insert a single row or multiple rows at once, and you can also use the NULL, NOT NULL, and DEFAULT constraints to define how values are inserted.",source:"@site/docs/sql-syntax/statements/data-manipulation/insert.md",sourceDirName:"sql-syntax/statements/data-manipulation",slug:"/sql-syntax/statements/data-manipulation/insert",permalink:"/docs/0.16.0/sql-syntax/statements/data-manipulation/insert",draft:!1,tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"autoSidebar",previous:{title:"ALTER TABLE",permalink:"/docs/0.16.0/sql-syntax/statements/data-definition/alter-table"},next:{title:"UPDATE",permalink:"/docs/0.16.0/sql-syntax/statements/data-manipulation/update"}},s={},u=[{value:"Basic INSERT Syntax",id:"basic-insert-syntax",level:2},{value:"Handling NULL, NOT NULL, and DEFAULT Constraints",id:"handling-null-not-null-and-default-constraints",level:2},{value:"Examples",id:"examples",level:2},{value:"Basic INSERT",id:"basic-insert",level:3},{value:"Inserting Multiple Rows",id:"inserting-multiple-rows",level:3},{value:"Inserting with Omitted Columns",id:"inserting-with-omitted-columns",level:3},{value:"Handling NOT NULL Constraint",id:"handling-not-null-constraint",level:3}],p={toc:u},m="wrapper";function c(e){let{components:n,...t}=e;return(0,r.yg)(m,(0,a.A)({},p,t,{components:n,mdxType:"MDXLayout"}),(0,r.yg)("h1",{id:"insert"},"INSERT"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"INSERT")," statement is used to insert new records into a table. You can insert a single row or multiple rows at once, and you can also use the ",(0,r.yg)("inlineCode",{parentName:"p"},"NULL"),", ",(0,r.yg)("inlineCode",{parentName:"p"},"NOT NULL"),", and ",(0,r.yg)("inlineCode",{parentName:"p"},"DEFAULT")," constraints to define how values are inserted."),(0,r.yg)("h2",{id:"basic-insert-syntax"},"Basic INSERT Syntax"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO table_name (column1, column2, column3, ...)\nVALUES\n (value1, value2, value3, ...),\n (value4, value5, value6, ...),\n ...\n;\n")),(0,r.yg)("h2",{id:"handling-null-not-null-and-default-constraints"},"Handling NULL, NOT NULL, and DEFAULT Constraints"),(0,r.yg)("p",null,"When inserting data into a table, the database handles ",(0,r.yg)("inlineCode",{parentName:"p"},"NULL"),", ",(0,r.yg)("inlineCode",{parentName:"p"},"NOT NULL"),", and ",(0,r.yg)("inlineCode",{parentName:"p"},"DEFAULT")," constraints as follows:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},(0,r.yg)("strong",{parentName:"p"},"NULL"),": If a column is defined with the ",(0,r.yg)("inlineCode",{parentName:"p"},"NULL")," constraint (or no constraint is provided), you can insert a ",(0,r.yg)("inlineCode",{parentName:"p"},"NULL")," value or omit the column in the ",(0,r.yg)("inlineCode",{parentName:"p"},"INSERT")," statement. The database will store a ",(0,r.yg)("inlineCode",{parentName:"p"},"NULL")," value for the omitted column.")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},(0,r.yg)("strong",{parentName:"p"},"NOT NULL"),": If a column is defined with the ",(0,r.yg)("inlineCode",{parentName:"p"},"NOT NULL")," constraint, you must provide a value for the column in the ",(0,r.yg)("inlineCode",{parentName:"p"},"INSERT")," statement. If you try to insert a ",(0,r.yg)("inlineCode",{parentName:"p"},"NULL")," value or omit the column, the database will return an error.")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},(0,r.yg)("strong",{parentName:"p"},"DEFAULT"),": If a column is defined with a ",(0,r.yg)("inlineCode",{parentName:"p"},"DEFAULT")," value, you can omit the column in the ",(0,r.yg)("inlineCode",{parentName:"p"},"INSERT")," statement. The database will automatically use the default value for the omitted column."))),(0,r.yg)("h2",{id:"examples"},"Examples"),(0,r.yg)("p",null,"Consider the following ",(0,r.yg)("inlineCode",{parentName:"p"},"Test")," table:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE Test (\n id INTEGER DEFAULT 1,\n num INTEGER NULL,\n name TEXT NOT NULL,\n);\n")),(0,r.yg)("h3",{id:"basic-insert"},"Basic INSERT"),(0,r.yg)("p",null,"To insert a single row:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO Test (id, num, name) VALUES (1, 2, 'Hi boo');\n")),(0,r.yg)("h3",{id:"inserting-multiple-rows"},"Inserting Multiple Rows"),(0,r.yg)("p",null,"To insert multiple rows at once:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO Test (id, num, name)\nVALUES\n (3, 9, 'Kitty!'),\n (2, 7, 'Monsters');\n")),(0,r.yg)("h3",{id:"inserting-with-omitted-columns"},"Inserting with Omitted Columns"),(0,r.yg)("p",null,"If you want to insert a row without specifying a value for a column with a ",(0,r.yg)("inlineCode",{parentName:"p"},"DEFAULT")," constraint, you can simply omit the column:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO Test (num, name) VALUES (28, 'Wazowski');\n")),(0,r.yg)("p",null,"For columns with ",(0,r.yg)("inlineCode",{parentName:"p"},"NULL")," constraint, you can either omit the column or explicitly insert a ",(0,r.yg)("inlineCode",{parentName:"p"},"NULL")," value:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO Test (name) VALUES ('The end');\n")),(0,r.yg)("h3",{id:"handling-not-null-constraint"},"Handling NOT NULL Constraint"),(0,r.yg)("p",null,"If you try to insert a row without specifying a value for a column with the ",(0,r.yg)("inlineCode",{parentName:"p"},"NOT NULL")," constraint, the database will return an error:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},'INSERT INTO Test (id, num) VALUES (1, 10);\n-- Error: LackOfRequiredColumn("name")\n')))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/e06425d1.7677941c.js b/docs/0.16.0/assets/js/e06425d1.7677941c.js new file mode 100644 index 00000000..d349b6c9 --- /dev/null +++ b/docs/0.16.0/assets/js/e06425d1.7677941c.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[4704],{5680:(e,t,n)=>{n.d(t,{xA:()=>u,yg:()=>h});var r=n(6540);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?l(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):l(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},l=Object.keys(e);for(r=0;r<l.length;r++)n=l[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(r=0;r<l.length;r++)n=l[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var o=r.createContext({}),c=function(e){var t=r.useContext(o),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},u=function(e){var t=c(e.components);return r.createElement(o.Provider,{value:t},e.children)},p="mdxType",g={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},y=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,l=e.originalType,o=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=c(n),y=a,h=p["".concat(o,".").concat(y)]||p[y]||g[y]||l;return n?r.createElement(h,i(i({ref:t},u),{},{components:n})):r.createElement(h,i({ref:t},u))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var l=n.length,i=new Array(l);i[0]=y;var s={};for(var o in t)hasOwnProperty.call(t,o)&&(s[o]=t[o]);s.originalType=e,s[p]="string"==typeof e?e:a,i[1]=s;for(var c=2;c<l;c++)i[c]=n[c];return r.createElement.apply(null,i)}return r.createElement.apply(null,n)}y.displayName="MDXCreateElement"},5706:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>o,contentTitle:()=>i,default:()=>g,frontMatter:()=>l,metadata:()=>s,toc:()=>c});var r=n(8168),a=(n(6540),n(5680));const l={},i="ASCII",s={unversionedId:"sql-syntax/functions/text/ascii",id:"sql-syntax/functions/text/ascii",title:"ASCII",description:"The ASCII function in SQL returns the ASCII value for the first character of the specified string.",source:"@site/docs/sql-syntax/functions/text/ascii.md",sourceDirName:"sql-syntax/functions/text",slug:"/sql-syntax/functions/text/ascii",permalink:"/docs/0.16.0/sql-syntax/functions/text/ascii",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"UUID",permalink:"/docs/0.16.0/sql-syntax/data-types/uuid"},next:{title:"CHR",permalink:"/docs/0.16.0/sql-syntax/functions/text/chr"}},o={},c=[{value:"Syntax",id:"syntax",level:2},{value:"Parameters",id:"parameters",level:2},{value:"Examples",id:"examples",level:2}],u={toc:c},p="wrapper";function g(e){let{components:t,...n}=e;return(0,a.yg)(p,(0,r.A)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"ascii"},"ASCII"),(0,a.yg)("p",null,"The ASCII function in SQL returns the ASCII value for the first character of the specified string. "),(0,a.yg)("h2",{id:"syntax"},"Syntax"),(0,a.yg)("p",null,"The syntax for the ASCII function in SQL is:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"ASCII ( single_character_text )\n")),(0,a.yg)("h2",{id:"parameters"},"Parameters"),(0,a.yg)("ul",null,(0,a.yg)("li",{parentName:"ul"},(0,a.yg)("inlineCode",{parentName:"li"},"single_character_text"),": This is the string that the ASCII value should be returned for. It should be a single character string. ")),(0,a.yg)("h2",{id:"examples"},"Examples"),(0,a.yg)("p",null,"Let's consider a few examples to understand how to use the ASCII function."),(0,a.yg)("p",null,"To get the ASCII value of a character:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"VALUES(ASCII('A'));\n")),(0,a.yg)("p",null,"This will return ",(0,a.yg)("inlineCode",{parentName:"p"},"65"),", which is the ASCII value for 'A'."),(0,a.yg)("p",null,"Please note that the ASCII function expects a single character value. If a string with more than one character is passed, it will throw an error. For instance:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"VALUES(ASCII('AB'));\n")),(0,a.yg)("p",null,"This will throw an error because 'AB' contains more than one character."),(0,a.yg)("p",null,"You can also use the ASCII function in a SELECT statement. Consider the following table named 'Ascii':"),(0,a.yg)("table",null,(0,a.yg)("thead",{parentName:"table"},(0,a.yg)("tr",{parentName:"thead"},(0,a.yg)("th",{parentName:"tr",align:null},"id"),(0,a.yg)("th",{parentName:"tr",align:null},"text"))),(0,a.yg)("tbody",{parentName:"table"},(0,a.yg)("tr",{parentName:"tbody"},(0,a.yg)("td",{parentName:"tr",align:null},"1"),(0,a.yg)("td",{parentName:"tr",align:null},"'F'")))),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE Ascii (\n id INTEGER,\n text TEXT\n);\nINSERT INTO Ascii VALUES (1, 'F');\n")),(0,a.yg)("p",null,"You can select the ASCII value of the 'text' column:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT ASCII(text) AS ascii FROM Ascii;\n")),(0,a.yg)("p",null,"This will return ",(0,a.yg)("inlineCode",{parentName:"p"},"70"),", which is the ASCII value for 'F'."),(0,a.yg)("p",null,"The ASCII function can also take a string directly:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT ASCII('a') AS ascii FROM Ascii;\n")),(0,a.yg)("p",null,"This will return ",(0,a.yg)("inlineCode",{parentName:"p"},"97"),", which is the ASCII value for 'a'."),(0,a.yg)("p",null,"If a non-ASCII character is passed to the function, it will throw an error. For instance:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT ASCII('\u3131') AS ascii FROM Ascii;\n")),(0,a.yg)("p",null,"This will throw an error because '\u3131' is not an ASCII character."),(0,a.yg)("p",null,"If no argument is passed to the ASCII function, it will also throw an error:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT ASCII() AS ascii FROM Ascii;\n")),(0,a.yg)("p",null,"This will throw an error because the ASCII function expects one argument."),(0,a.yg)("p",null,"Remember, the ASCII function expects a single character. If the column value contains more than one character, it will throw an error:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO Ascii VALUES (1, 'Foo');\nSELECT ASCII(text) AS ascii FROM Ascii;\n")),(0,a.yg)("p",null,"This will throw an error because 'Foo' contains more than one character."))}g.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/e10f7c24.1537803d.js b/docs/0.16.0/assets/js/e10f7c24.1537803d.js new file mode 100644 index 00000000..218d4105 --- /dev/null +++ b/docs/0.16.0/assets/js/e10f7c24.1537803d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[6803],{5680:(e,n,t)=>{t.d(n,{xA:()=>p,yg:()=>y});var a=t(6540);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function l(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function o(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?l(Object(t),!0).forEach((function(n){r(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):l(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function i(e,n){if(null==e)return{};var t,a,r=function(e,n){if(null==e)return{};var t,a,r={},l=Object.keys(e);for(a=0;a<l.length;a++)t=l[a],n.indexOf(t)>=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a<l.length;a++)t=l[a],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var s=a.createContext({}),u=function(e){var n=a.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):o(o({},n),e)),t},p=function(e){var n=u(e.components);return a.createElement(s.Provider,{value:n},e.children)},g="mdxType",c={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},d=a.forwardRef((function(e,n){var t=e.components,r=e.mdxType,l=e.originalType,s=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),g=u(t),d=r,y=g["".concat(s,".").concat(d)]||g[d]||c[d]||l;return t?a.createElement(y,o(o({ref:n},p),{},{components:t})):a.createElement(y,o({ref:n},p))}));function y(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var l=t.length,o=new Array(l);o[0]=d;var i={};for(var s in n)hasOwnProperty.call(n,s)&&(i[s]=n[s]);i.originalType=e,i[g]="string"==typeof e?e:r,o[1]=i;for(var u=2;u<l;u++)o[u]=t[u];return a.createElement.apply(null,o)}return a.createElement.apply(null,t)}d.displayName="MDXCreateElement"},7365:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>s,contentTitle:()=>o,default:()=>c,frontMatter:()=>l,metadata:()=>i,toc:()=>u});var a=t(8168),r=(t(6540),t(5680));const l={sidebar_position:2},o="JavaScript (Web Browser)",i={unversionedId:"getting-started/javascript-web",id:"getting-started/javascript-web",title:"JavaScript (Web Browser)",description:"GlueSQL is a SQL database engine written in Rust, compiled to WebAssembly, and can be used in JavaScript. This guide will walk you through the process of installing and using the GlueSQL package.",source:"@site/docs/getting-started/javascript-web.md",sourceDirName:"getting-started",slug:"/getting-started/javascript-web",permalink:"/docs/0.16.0/getting-started/javascript-web",draft:!1,tags:[],version:"current",sidebarPosition:2,frontMatter:{sidebar_position:2},sidebar:"autoSidebar",previous:{title:"Rust",permalink:"/docs/0.16.0/getting-started/rust"},next:{title:"Node.js",permalink:"/docs/0.16.0/getting-started/nodejs"}},s={},u=[{value:"Installation",id:"installation",level:2},{value:"Usage",id:"usage",level:2},{value:"JavaScript Modules",id:"javascript-modules",level:3},{value:"Webpack",id:"webpack",level:3},{value:"Rollup",id:"rollup",level:3},{value:"Supported Storage Engines",id:"supported-storage-engines",level:2}],p={toc:u},g="wrapper";function c(e){let{components:n,...t}=e;return(0,r.yg)(g,(0,a.A)({},p,t,{components:n,mdxType:"MDXLayout"}),(0,r.yg)("h1",{id:"javascript-web-browser"},"JavaScript (Web Browser)"),(0,r.yg)("p",null,"GlueSQL is a SQL database engine written in Rust, compiled to WebAssembly, and can be used in JavaScript. This guide will walk you through the process of installing and using the GlueSQL package."),(0,r.yg)("h2",{id:"installation"},"Installation"),(0,r.yg)("p",null,"Installing GlueSQL is as simple as running the following command:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"npm install gluesql\n")),(0,r.yg)("p",null,"In your ",(0,r.yg)("inlineCode",{parentName:"p"},"package.json"),", it will be added to the dependencies list as follows:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-json"},'{\n "dependencies": {\n "gluesql": "latest"\n }\n}\n')),(0,r.yg)("h2",{id:"usage"},"Usage"),(0,r.yg)("p",null,"GlueSQL can be used in different environments. Here we will look at how to use it with JavaScript modules, Webpack, and Rollup."),(0,r.yg)("h3",{id:"javascript-modules"},"JavaScript Modules"),(0,r.yg)("p",null,"In an HTML file, you can use GlueSQL by importing it with a script tag:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-html"},"<script type=\"module\">\n import { gluesql } from 'gluesql';\n\n async function main() {\n const db = await gluesql();\n await db.loadIndexedDB();\n\n const result = await db.query(`\n CREATE TABLE Foo (id INTEGER) ENGINE = memory;\n INSERT INTO Foo (1, 'glue'), (2, 'sql');\n SELECT * FROM Foo;\n `);\n\n console.log(result);\n }\n<\/script>\n")),(0,r.yg)("h3",{id:"webpack"},"Webpack"),(0,r.yg)("p",null,"For Webpack, the usage is almost the same as JavaScript modules:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-javascript"},"import { gluesql } from 'gluesql';\n\nasync function run() {\n const db = await gluesql();\n await db.loadIndexedDB();\n\n const result = await db.query(`\n CREATE TABLE Foo (id INTEGER) ENGINE = memory;\n INSERT INTO Foo VALUES (1, 'glue'), (2, 'sql');\n SELECT * FROM Foo;\n `);\n\n console.log(result);\n}\n")),(0,r.yg)("h3",{id:"rollup"},"Rollup"),(0,r.yg)("p",null,"For Rollup, you need to adjust your import statement and add some configurations to your ",(0,r.yg)("inlineCode",{parentName:"p"},"rollup.config.js")," file."),(0,r.yg)("p",null,"First, modify your import statement as follows:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-javascript"},"import { gluesql } from 'gluesql/gluesql.rollup';\n// ...\n")),(0,r.yg)("p",null,"Second, add the following configurations to your ",(0,r.yg)("inlineCode",{parentName:"p"},"rollup.config.js")," file:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-javascript"},"import resolve from '@rollup/plugin-node-resolve';\nimport { wasm } from '@rollup/plugin-wasm';\n\nexport default {\n input: 'main.js',\n output: {\n file: 'dist/bundle.js',\n format: 'iife',\n },\n plugins: [\n resolve({ browser: true }),\n wasm({ targetEnv: 'auto-inline' }),\n ],\n};\n")),(0,r.yg)("p",null,"These configurations allow Rollup to correctly handle WebAssembly modules and resolve dependencies for browsers."),(0,r.yg)("p",null,"Don't forget to run the ",(0,r.yg)("inlineCode",{parentName:"p"},"rollup")," command to bundle your JavaScript files:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"rollup -c\n")),(0,r.yg)("p",null,"Now, you can use GlueSQL in your Rollup project as you would in any other JavaScript module."),(0,r.yg)("h2",{id:"supported-storage-engines"},"Supported Storage Engines"),(0,r.yg)("p",null,"GlueSQL supports four storage types: In-Memory Storage, Local Storage, Session Storage, and IndexedDB. "),(0,r.yg)("p",null,"You can specify the storage type when creating a table using the ",(0,r.yg)("inlineCode",{parentName:"p"},"ENGINE")," clause:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"For In-Memory Storage: ",(0,r.yg)("inlineCode",{parentName:"li"},"ENGINE = memory")),(0,r.yg)("li",{parentName:"ul"},"For Local Storage: ",(0,r.yg)("inlineCode",{parentName:"li"},"ENGINE = localStorage")),(0,r.yg)("li",{parentName:"ul"},"For Session Storage: ",(0,r.yg)("inlineCode",{parentName:"li"},"ENGINE = sessionStorage")),(0,r.yg)("li",{parentName:"ul"},"For IndexedDB: ",(0,r.yg)("inlineCode",{parentName:"li"},"ENGINE = indexedDB"))),(0,r.yg)("p",null,"For example:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE Foo (id INTEGER) ENGINE = memory;\n")))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/e158c27a.75d2740d.js b/docs/0.16.0/assets/js/e158c27a.75d2740d.js new file mode 100644 index 00000000..071bb125 --- /dev/null +++ b/docs/0.16.0/assets/js/e158c27a.75d2740d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[321],{5680:(e,n,t)=>{t.d(n,{xA:()=>c,yg:()=>y});var a=t(6540);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function o(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function l(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?o(Object(t),!0).forEach((function(n){r(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):o(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function s(e,n){if(null==e)return{};var t,a,r=function(e,n){if(null==e)return{};var t,a,r={},o=Object.keys(e);for(a=0;a<o.length;a++)t=o[a],n.indexOf(t)>=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a<o.length;a++)t=o[a],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var i=a.createContext({}),p=function(e){var n=a.useContext(i),t=n;return e&&(t="function"==typeof e?e(n):l(l({},n),e)),t},c=function(e){var n=p(e.components);return a.createElement(i.Provider,{value:n},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},g=a.forwardRef((function(e,n){var t=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),d=p(t),g=r,y=d["".concat(i,".").concat(g)]||d[g]||u[g]||o;return t?a.createElement(y,l(l({ref:n},c),{},{components:t})):a.createElement(y,l({ref:n},c))}));function y(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var o=t.length,l=new Array(o);l[0]=g;var s={};for(var i in n)hasOwnProperty.call(n,i)&&(s[i]=n[i]);s.originalType=e,s[d]="string"==typeof e?e:r,l[1]=s;for(var p=2;p<o;p++)l[p]=t[p];return a.createElement.apply(null,l)}return a.createElement.apply(null,t)}g.displayName="MDXCreateElement"},7914:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>i,contentTitle:()=>l,default:()=>u,frontMatter:()=>o,metadata:()=>s,toc:()=>p});var a=t(8168),r=(t(6540),t(5680));const o={sidebar_position:4},l="Transaction",s={unversionedId:"sql-syntax/statements/transaction",id:"sql-syntax/statements/transaction",title:"Transaction",description:"Transactions in SQL are a series of queries that are executed as a single unit of work. In GlueSQL, transactions help to ensure the consistency and integrity of the database. They follow the ACID properties: Atomicity, Consistency, Isolation, and Durability.",source:"@site/docs/sql-syntax/statements/transaction.md",sourceDirName:"sql-syntax/statements",slug:"/sql-syntax/statements/transaction",permalink:"/docs/0.16.0/sql-syntax/statements/transaction",draft:!1,tags:[],version:"current",sidebarPosition:4,frontMatter:{sidebar_position:4},sidebar:"autoSidebar",previous:{title:"DELETE",permalink:"/docs/0.16.0/sql-syntax/statements/data-manipulation/delete"},next:{title:"SHOW TABLES",permalink:"/docs/0.16.0/sql-syntax/statements/metadata/show-tables"}},i={},p=[{value:"BEGIN TRANSACTION",id:"begin-transaction",level:2},{value:"COMMIT TRANSACTION",id:"commit-transaction",level:2},{value:"ROLLBACK TRANSACTION",id:"rollback-transaction",level:2},{value:"Example",id:"example",level:2},{value:"Inserting Data",id:"inserting-data",level:3},{value:"Deleting Data",id:"deleting-data",level:3},{value:"Updating Data",id:"updating-data",level:3}],c={toc:p},d="wrapper";function u(e){let{components:n,...t}=e;return(0,r.yg)(d,(0,a.A)({},c,t,{components:n,mdxType:"MDXLayout"}),(0,r.yg)("h1",{id:"transaction"},"Transaction"),(0,r.yg)("p",null,"Transactions in SQL are a series of queries that are executed as a single unit of work. In GlueSQL, transactions help to ensure the consistency and integrity of the database. They follow the ACID properties: Atomicity, Consistency, Isolation, and Durability."),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},"Note: In GlueSQL, transactions are an optional feature. Support for transactions depends on the storage engine being used. Currently, only ",(0,r.yg)("inlineCode",{parentName:"strong"},"SledStorage")," supports transactions, but there are plans to add support for other storage engines in the future. Transaction isolation levels may also vary depending on the storage engine. For example, the current transaction isolation level for ",(0,r.yg)("inlineCode",{parentName:"strong"},"SledStorage")," is SNAPSHOT ISOLATION.")),(0,r.yg)("h2",{id:"begin-transaction"},"BEGIN TRANSACTION"),(0,r.yg)("p",null,"To start a new transaction, use the ",(0,r.yg)("inlineCode",{parentName:"p"},"BEGIN")," keyword:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre"},"BEGIN;\n")),(0,r.yg)("h2",{id:"commit-transaction"},"COMMIT TRANSACTION"),(0,r.yg)("p",null,"To permanently save the changes made during the transaction, use the ",(0,r.yg)("inlineCode",{parentName:"p"},"COMMIT")," keyword:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre"},"COMMIT;\n")),(0,r.yg)("h2",{id:"rollback-transaction"},"ROLLBACK TRANSACTION"),(0,r.yg)("p",null,"To undo the changes made during the transaction and revert the database to its state before the transaction started, use the ",(0,r.yg)("inlineCode",{parentName:"p"},"ROLLBACK")," keyword:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre"},"ROLLBACK;\n")),(0,r.yg)("h2",{id:"example"},"Example"),(0,r.yg)("p",null,"Consider the following table ",(0,r.yg)("inlineCode",{parentName:"p"},"TxTest")," with columns ",(0,r.yg)("inlineCode",{parentName:"p"},"id")," (INTEGER) and ",(0,r.yg)("inlineCode",{parentName:"p"},"name")," (TEXT):"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE TxTest (\n id INTEGER,\n name TEXT\n);\n")),(0,r.yg)("p",null,"Insert sample data into the table:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO TxTest VALUES\n (1, 'Friday'),\n (2, 'Phone');\n")),(0,r.yg)("h3",{id:"inserting-data"},"Inserting Data"),(0,r.yg)("p",null,"Start a new transaction and insert a new row:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"BEGIN;\nINSERT INTO TxTest VALUES (3, 'New one');\n")),(0,r.yg)("p",null,"Rollback the transaction to undo the insertion:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"ROLLBACK;\n")),(0,r.yg)("p",null,"Now, start a new transaction and insert a new row with different data:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"BEGIN;\nINSERT INTO TxTest VALUES (3, 'Vienna');\nCOMMIT;\n")),(0,r.yg)("h3",{id:"deleting-data"},"Deleting Data"),(0,r.yg)("p",null,"Start a new transaction and delete a row:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"BEGIN;\nDELETE FROM TxTest WHERE id = 3;\nROLLBACK;\n")),(0,r.yg)("p",null,"The deletion will be undone due to the rollback. To permanently delete the row, commit the transaction:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"BEGIN;\nDELETE FROM TxTest WHERE id = 3;\nCOMMIT;\n")),(0,r.yg)("h3",{id:"updating-data"},"Updating Data"),(0,r.yg)("p",null,"Start a new transaction and update a row:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"BEGIN;\nUPDATE TxTest SET name = 'Sunday' WHERE id = 1;\nROLLBACK;\n")),(0,r.yg)("p",null,"The update will be undone due to the rollback. To permanently update the row, commit the transaction:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"BEGIN;\nUPDATE TxTest SET name = 'Sunday' WHERE id = 1;\nCOMMIT;\n")))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/e329d2fa.594a299b.js b/docs/0.16.0/assets/js/e329d2fa.594a299b.js new file mode 100644 index 00000000..8b80551c --- /dev/null +++ b/docs/0.16.0/assets/js/e329d2fa.594a299b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[805],{5680:(e,t,a)=>{a.d(t,{xA:()=>d,yg:()=>g});var r=a(6540);function n(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function o(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,r)}return a}function i(e){for(var t=1;t<arguments.length;t++){var a=null!=arguments[t]?arguments[t]:{};t%2?o(Object(a),!0).forEach((function(t){n(e,t,a[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(a)):o(Object(a)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(a,t))}))}return e}function s(e,t){if(null==e)return{};var a,r,n=function(e,t){if(null==e)return{};var a,r,n={},o=Object.keys(e);for(r=0;r<o.length;r++)a=o[r],t.indexOf(a)>=0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r<o.length;r++)a=o[r],t.indexOf(a)>=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(n[a]=e[a])}return n}var c=r.createContext({}),p=function(e){var t=r.useContext(c),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},d=function(e){var t=p(e.components);return r.createElement(c.Provider,{value:t},e.children)},l="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var a=e.components,n=e.mdxType,o=e.originalType,c=e.parentName,d=s(e,["components","mdxType","originalType","parentName"]),l=p(a),m=n,g=l["".concat(c,".").concat(m)]||l[m]||u[m]||o;return a?r.createElement(g,i(i({ref:t},d),{},{components:a})):r.createElement(g,i({ref:t},d))}));function g(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=a.length,i=new Array(o);i[0]=m;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[l]="string"==typeof e?e:n,i[1]=s;for(var p=2;p<o;p++)i[p]=a[p];return r.createElement.apply(null,i)}return r.createElement.apply(null,a)}m.displayName="MDXCreateElement"},5323:(e,t,a)=>{a.r(t),a.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>u,frontMatter:()=>o,metadata:()=>s,toc:()=>p});var r=a(8168),n=(a(6540),a(5680));const o={sidebar_position:9},i="Metadata",s={unversionedId:"storages/developing-custom-storages/store-traits/metadata",id:"storages/developing-custom-storages/store-traits/metadata",title:"Metadata",description:"The Metadata trait is an optional implementation for providing additional metadata support in GlueSQL. GlueSQL does not enforce any specific metadata implementation, allowing custom storage developers to decide which type of metadata, such as create time, modify time, etc., they want to provide.",source:"@site/docs/storages/developing-custom-storages/store-traits/metadata.md",sourceDirName:"storages/developing-custom-storages/store-traits",slug:"/storages/developing-custom-storages/store-traits/metadata",permalink:"/docs/0.16.0/storages/developing-custom-storages/store-traits/metadata",draft:!1,tags:[],version:"current",sidebarPosition:9,frontMatter:{sidebar_position:9},sidebar:"autoSidebar",previous:{title:"IndexMut",permalink:"/docs/0.16.0/storages/developing-custom-storages/store-traits/index-mut"},next:{title:"Using the Test Suite",permalink:"/docs/0.16.0/storages/developing-custom-storages/using-test-suite"}},c={},p=[],d={toc:p},l="wrapper";function u(e){let{components:t,...a}=e;return(0,n.yg)(l,(0,r.A)({},d,a,{components:t,mdxType:"MDXLayout"}),(0,n.yg)("h1",{id:"metadata"},"Metadata"),(0,n.yg)("p",null,"The ",(0,n.yg)("inlineCode",{parentName:"p"},"Metadata")," trait is an optional implementation for providing additional metadata support in GlueSQL. GlueSQL does not enforce any specific metadata implementation, allowing custom storage developers to decide which type of metadata, such as create time, modify time, etc., they want to provide."),(0,n.yg)("p",null,"Implementing the ",(0,n.yg)("inlineCode",{parentName:"p"},"Metadata")," trait can be beneficial in cases where users need to access and manage metadata related to tables, columns, or other database objects. This can help users understand the structure and properties of their data, ensuring proper management and organization."),(0,n.yg)("p",null,"Currently, the ",(0,n.yg)("inlineCode",{parentName:"p"},"Metadata")," trait supports the ",(0,n.yg)("inlineCode",{parentName:"p"},"scan_table_meta")," method for retrieving table metadata. The metadata provided by the storage can be queried using the data dictionary table ",(0,n.yg)("inlineCode",{parentName:"p"},"GLUE_TABLES"),"."),(0,n.yg)("pre",null,(0,n.yg)("code",{parentName:"pre",className:"language-rust"},"type ObjectName = String;\npub type MetaIter = Box<dyn Iterator<Item = Result<(ObjectName, HashMap<String, Value>)>>>;\n\n#[async_trait(?Send)]\npub trait Metadata {\n async fn scan_table_meta(&self) -> Result<MetaIter> {\n Ok(Box::new(empty()))\n }\n}\n")),(0,n.yg)("p",null,"By implementing the ",(0,n.yg)("inlineCode",{parentName:"p"},"Metadata")," trait, custom storage developers can provide users with a way to access and manage metadata related to various database objects. This can be particularly useful in situations where users need to understand the properties of their data or maintain a well-organized database structure."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/e46b95eb.b729c545.js b/docs/0.16.0/assets/js/e46b95eb.b729c545.js new file mode 100644 index 00000000..1ef5760d --- /dev/null +++ b/docs/0.16.0/assets/js/e46b95eb.b729c545.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[2883],{5680:(e,t,r)=>{r.d(t,{xA:()=>u,yg:()=>m});var n=r(6540);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function s(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?o(Object(r),!0).forEach((function(t){a(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):o(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function l(e,t){if(null==e)return{};var r,n,a=function(e,t){if(null==e)return{};var r,n,a={},o=Object.keys(e);for(n=0;n<o.length;n++)r=o[n],t.indexOf(r)>=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n<o.length;n++)r=o[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var i=n.createContext({}),c=function(e){var t=n.useContext(i),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},u=function(e){var t=c(e.components);return n.createElement(i.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},g=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,i=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=c(r),g=a,m=p["".concat(i,".").concat(g)]||p[g]||d[g]||o;return r?n.createElement(m,s(s({ref:t},u),{},{components:r})):n.createElement(m,s({ref:t},u))}));function m(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,s=new Array(o);s[0]=g;var l={};for(var i in t)hasOwnProperty.call(t,i)&&(l[i]=t[i]);l.originalType=e,l[p]="string"==typeof e?e:a,s[1]=l;for(var c=2;c<o;c++)s[c]=r[c];return n.createElement.apply(null,s)}return n.createElement.apply(null,r)}g.displayName="MDXCreateElement"},5618:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>i,contentTitle:()=>s,default:()=>d,frontMatter:()=>o,metadata:()=>l,toc:()=>c});var n=r(8168),a=(r(6540),r(5680));const o={},s="Shared Memory Storage",l={unversionedId:"storages/supported-storages/shared-memory-storage",id:"storages/supported-storages/shared-memory-storage",title:"Shared Memory Storage",description:"SharedMemoryStorage is a storage option designed to provide more comfortable usage of MemoryStorage in concurrent environments. Although it doesn't operate in parallel, it makes accessing the same data from multiple threads simultaneously more convenient.",source:"@site/docs/storages/supported-storages/shared-memory-storage.md",sourceDirName:"storages/supported-storages",slug:"/storages/supported-storages/shared-memory-storage",permalink:"/docs/0.16.0/storages/supported-storages/shared-memory-storage",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"Parquet Storage",permalink:"/docs/0.16.0/storages/supported-storages/parquet-storage"},next:{title:"Sled Storage",permalink:"/docs/0.16.0/storages/supported-storages/sled-storage"}},i={},c=[],u={toc:c},p="wrapper";function d(e){let{components:t,...r}=e;return(0,a.yg)(p,(0,n.A)({},u,r,{components:t,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"shared-memory-storage"},"Shared Memory Storage"),(0,a.yg)("p",null,"SharedMemoryStorage is a storage option designed to provide more comfortable usage of MemoryStorage in concurrent environments. Although it doesn't operate in parallel, it makes accessing the same data from multiple threads simultaneously more convenient."),(0,a.yg)("p",null,"The basic structure of SharedMemoryStorage is straightforward. It wraps the MemoryStorage with a read-write lock (",(0,a.yg)("inlineCode",{parentName:"p"},"RwLock"),") and an atomic reference count (",(0,a.yg)("inlineCode",{parentName:"p"},"Arc"),"):"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-rust"},"#[derive(Clone, Debug)]\npub struct SharedMemoryStorage {\n pub database: Arc<RwLock<MemoryStorage>>,\n}\n")),(0,a.yg)("p",null,"This structure allows you to clone the storage instance and use it effortlessly across multiple threads. Regardless of how many times the storage is cloned, all storage instances will refer to the same data."),(0,a.yg)("p",null,"Here's an example of how to use SharedMemoryStorage in a concurrent environment:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-rust"},'use gluesql_core::prelude::{Glue, Payload, Value};\n\nasync fn concurrent_access() {\n let storage = SharedMemoryStorage::new();\n\n let mut glue = Glue::new(storage.clone());\n glue.execute("CREATE TABLE Thread (id INTEGER);").unwrap();\n\n let thread_1 = tokio::spawn({\n let storage = storage.clone();\n async {\n let mut glue = Glue::new(storage);\n glue.execute("INSERT INTO Thread VALUES(1)").unwrap();\n }\n });\n\n let thread_2 = tokio::spawn({\n let storage = storage.clone();\n async {\n let mut glue = Glue::new(storage);\n glue.execute("INSERT INTO Thread VALUES(2)").unwrap();\n }\n });\n\n let _ = tokio::join!(thread_1, thread_2);\n\n let actual = glue.execute("SELECT * FROM Thread").unwrap();\n let expected = vec![Payload::Select {\n labels: vec!["id".to_owned()],\n rows: vec![vec![Value::I64(1)], vec![Value::I64(2)]],\n }];\n assert_eq!(actual, expected);\n}\n')),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"concurrent_access")," function above illustrates how to concurrently insert data into the same table from different threads. After inserting data from two separate threads, we can confirm that the inserted data is correctly stored by executing a SELECT statement."),(0,a.yg)("p",null,"SharedMemoryStorage is primarily intended for convenience rather than performance when dealing with multiple threads. As you can see from the structure, placing a read-write lock (",(0,a.yg)("inlineCode",{parentName:"p"},"RwLock"),") on the entire database is not recommended for performance reasons when handling data concurrently from multiple threads. Therefore, it's best to use SharedMemoryStorage or MemoryStorage depending on the situation."),(0,a.yg)("p",null,"SharedMemoryStorage is only available in the Rust environment, and its implementation of the ",(0,a.yg)("inlineCode",{parentName:"p"},"Store")," trait is identical to that of MemoryStorage."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/e4f709d1.622e5fc6.js b/docs/0.16.0/assets/js/e4f709d1.622e5fc6.js new file mode 100644 index 00000000..fe307f69 --- /dev/null +++ b/docs/0.16.0/assets/js/e4f709d1.622e5fc6.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[4253],{5680:(e,t,n)=>{n.d(t,{xA:()=>u,yg:()=>g});var r=n(6540);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},o=Object.keys(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),c=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},u=function(e){var t=c(e.components);return r.createElement(s.Provider,{value:t},e.children)},m="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},f=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),m=c(n),f=a,g=m["".concat(s,".").concat(f)]||m[f]||p[f]||o;return n?r.createElement(g,i(i({ref:t},u),{},{components:n})):r.createElement(g,i({ref:t},u))}));function g(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=f;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[m]="string"==typeof e?e:a,i[1]=l;for(var c=2;c<o;c++)i[c]=n[c];return r.createElement.apply(null,i)}return r.createElement.apply(null,n)}f.displayName="MDXCreateElement"},2864:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>p,frontMatter:()=>o,metadata:()=>l,toc:()=>c});var r=n(8168),a=(n(6540),n(5680));const o={},i="LCM",l={unversionedId:"sql-syntax/functions/math/lcm",id:"sql-syntax/functions/math/lcm",title:"LCM",description:"The LCM function is used to find the least common multiple (LCM) of two integers. It takes two INTEGER arguments and returns an INTEGER value representing the least common multiple of the given integers.",source:"@site/docs/sql-syntax/functions/math/lcm.md",sourceDirName:"sql-syntax/functions/math",slug:"/sql-syntax/functions/math/lcm",permalink:"/docs/0.16.0/sql-syntax/functions/math/lcm",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"GCD",permalink:"/docs/0.16.0/sql-syntax/functions/math/gcd"},next:{title:"LN",permalink:"/docs/0.16.0/sql-syntax/functions/math/ln"}},s={},c=[{value:"Example",id:"example",level:2},{value:"Errors",id:"errors",level:2}],u={toc:c},m="wrapper";function p(e){let{components:t,...n}=e;return(0,a.yg)(m,(0,r.A)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"lcm"},"LCM"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"LCM")," function is used to find the least common multiple (LCM) of two integers. It takes two INTEGER arguments and returns an INTEGER value representing the least common multiple of the given integers."),(0,a.yg)("h2",{id:"example"},"Example"),(0,a.yg)("p",null,"The following example demonstrates the usage of the ",(0,a.yg)("inlineCode",{parentName:"p"},"LCM")," function in a SQL query:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE LcmI64 (\n left INTEGER NULL,\n right INTEGER NULL\n);\n\nINSERT INTO LcmI64 VALUES (0, 3), (2, 4), (6, 8), (3, 5), (1, NULL), (NULL, 1);\n\nSELECT LCM(left, right) AS test FROM LcmI64;\n")),(0,a.yg)("p",null,"This will return the following result:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre"},"test\n0\n4\n24\n15\nNULL\nNULL\n")),(0,a.yg)("h2",{id:"errors"},"Errors"),(0,a.yg)("ol",null,(0,a.yg)("li",{parentName:"ol"},"If either of the arguments is not of INTEGER type, a ",(0,a.yg)("inlineCode",{parentName:"li"},"FunctionRequiresIntegerValue")," error will be raised."),(0,a.yg)("li",{parentName:"ol"},"If the number of arguments provided to the function is not equal to 2, a ",(0,a.yg)("inlineCode",{parentName:"li"},"FunctionArgsLengthNotMatching")," error will be raised."),(0,a.yg)("li",{parentName:"ol"},"If either of the arguments is the minimum i64 value (",(0,a.yg)("inlineCode",{parentName:"li"},"-9223372036854775808"),"), an overflow occurs when attempting to calculate the gcd, which is then used in the lcm calculation. In this case, an ",(0,a.yg)("inlineCode",{parentName:"li"},"GcdLcmOverflowError")," is raised."),(0,a.yg)("li",{parentName:"ol"},"If the calculated result of lcm is outside the valid range of i64 (",(0,a.yg)("inlineCode",{parentName:"li"},"-9223372036854775808")," to ",(0,a.yg)("inlineCode",{parentName:"li"},"9223372036854775807"),"), a ",(0,a.yg)("inlineCode",{parentName:"li"},"LcmResultOutOfRange")," error is raised. This may occur with large prime numbers.")))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/e5f53749.cd665626.js b/docs/0.16.0/assets/js/e5f53749.cd665626.js new file mode 100644 index 00000000..98831307 --- /dev/null +++ b/docs/0.16.0/assets/js/e5f53749.cd665626.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[8465],{5680:(e,t,n)=>{n.d(t,{xA:()=>u,yg:()=>y});var r=n(6540);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?a(Object(n),!0).forEach((function(t){o(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):a(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function c(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},a=Object.keys(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=r.createContext({}),l=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},u=function(e){var t=l(e.components);return r.createElement(s.Provider,{value:t},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,s=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),d=l(n),m=o,y=d["".concat(s,".").concat(m)]||d[m]||p[m]||a;return n?r.createElement(y,i(i({ref:t},u),{},{components:n})):r.createElement(y,i({ref:t},u))}));function y(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,i=new Array(a);i[0]=m;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c[d]="string"==typeof e?e:o,i[1]=c;for(var l=2;l<a;l++)i[l]=n[l];return r.createElement.apply(null,i)}return r.createElement.apply(null,n)}m.displayName="MDXCreateElement"},7790:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>p,frontMatter:()=>a,metadata:()=>c,toc:()=>l});var r=n(8168),o=(n(6540),n(5680));const a={},i="Data Joining",c={unversionedId:"ast-builder/statements/querying/data-joining",id:"ast-builder/statements/querying/data-joining",title:"Data Joining",description:"Todo",source:"@site/docs/ast-builder/statements/querying/data-joining.md",sourceDirName:"ast-builder/statements/querying",slug:"/ast-builder/statements/querying/data-joining",permalink:"/docs/0.16.0/ast-builder/statements/querying/data-joining",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"Data Injection",permalink:"/docs/0.16.0/ast-builder/statements/querying/data-injection"},next:{title:"Data Selection and Projection",permalink:"/docs/0.16.0/ast-builder/statements/querying/data-selection-and-projection"}},s={},l=[{value:"Todo",id:"todo",level:2}],u={toc:l},d="wrapper";function p(e){let{components:t,...n}=e;return(0,o.yg)(d,(0,r.A)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,o.yg)("h1",{id:"data-joining"},"Data Joining"),(0,o.yg)("h2",{id:"todo"},"Todo"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre"},"- JOIN: Combines rows from two or more tables based on a related column between them.\n")))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/e68f8ad6.c1a8db19.js b/docs/0.16.0/assets/js/e68f8ad6.c1a8db19.js new file mode 100644 index 00000000..ca2b8cb7 --- /dev/null +++ b/docs/0.16.0/assets/js/e68f8ad6.c1a8db19.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[1947],{5680:(e,n,t)=>{t.d(n,{xA:()=>c,yg:()=>g});var a=t(6540);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function i(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function o(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?i(Object(t),!0).forEach((function(n){r(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):i(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function l(e,n){if(null==e)return{};var t,a,r=function(e,n){if(null==e)return{};var t,a,r={},i=Object.keys(e);for(a=0;a<i.length;a++)t=i[a],n.indexOf(t)>=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a<i.length;a++)t=i[a],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var s=a.createContext({}),u=function(e){var n=a.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):o(o({},n),e)),t},c=function(e){var n=u(e.components);return a.createElement(s.Provider,{value:n},e.children)},p="mdxType",y={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},d=a.forwardRef((function(e,n){var t=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),p=u(t),d=r,g=p["".concat(s,".").concat(d)]||p[d]||y[d]||i;return t?a.createElement(g,o(o({ref:n},c),{},{components:t})):a.createElement(g,o({ref:n},c))}));function g(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var i=t.length,o=new Array(i);o[0]=d;var l={};for(var s in n)hasOwnProperty.call(n,s)&&(l[s]=n[s]);l.originalType=e,l[p]="string"==typeof e?e:r,o[1]=l;for(var u=2;u<i;u++)o[u]=t[u];return a.createElement.apply(null,o)}return a.createElement.apply(null,t)}d.displayName="MDXCreateElement"},2944:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>s,contentTitle:()=>o,default:()=>y,frontMatter:()=>i,metadata:()=>l,toc:()=>u});var a=t(8168),r=(t(6540),t(5680));const i={sidebar_position:1},o="BOOLEAN",l={unversionedId:"sql-syntax/data-types/boolean",id:"sql-syntax/data-types/boolean",title:"BOOLEAN",description:"The BOOLEAN data type in SQL is used to store boolean values, which can be either TRUE or FALSE. This data type is useful for representing binary states or conditions in your data.",source:"@site/docs/sql-syntax/data-types/boolean.md",sourceDirName:"sql-syntax/data-types",slug:"/sql-syntax/data-types/boolean",permalink:"/docs/0.16.0/sql-syntax/data-types/boolean",draft:!1,tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"autoSidebar",previous:{title:"Data Dictionary",permalink:"/docs/0.16.0/sql-syntax/statements/metadata/data-dictionary"},next:{title:"Integer Types",permalink:"/docs/0.16.0/sql-syntax/data-types/integers"}},s={},u=[{value:"Creating a table with a BOOLEAN column",id:"creating-a-table-with-a-boolean-column",level:2},{value:"Inserting data into the BOOLEAN column",id:"inserting-data-into-the-boolean-column",level:2},{value:"Querying data from the BOOLEAN column",id:"querying-data-from-the-boolean-column",level:2},{value:"Casting between BOOLEAN and INTEGER",id:"casting-between-boolean-and-integer",level:2},{value:"Conclusion",id:"conclusion",level:2}],c={toc:u},p="wrapper";function y(e){let{components:n,...t}=e;return(0,r.yg)(p,(0,a.A)({},c,t,{components:n,mdxType:"MDXLayout"}),(0,r.yg)("h1",{id:"boolean"},"BOOLEAN"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"BOOLEAN")," data type in SQL is used to store boolean values, which can be either ",(0,r.yg)("inlineCode",{parentName:"p"},"TRUE")," or ",(0,r.yg)("inlineCode",{parentName:"p"},"FALSE"),". This data type is useful for representing binary states or conditions in your data."),(0,r.yg)("p",null,"Here's an example of how to create a table, insert data, and query data using the ",(0,r.yg)("inlineCode",{parentName:"p"},"BOOLEAN")," data type:"),(0,r.yg)("h2",{id:"creating-a-table-with-a-boolean-column"},"Creating a table with a BOOLEAN column"),(0,r.yg)("p",null,"To create a table with a BOOLEAN column, use the following SQL syntax:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE user_active (username TEXT, is_active BOOLEAN);\n")),(0,r.yg)("h2",{id:"inserting-data-into-the-boolean-column"},"Inserting data into the BOOLEAN column"),(0,r.yg)("p",null,"To insert data into the BOOLEAN column, provide the boolean values as ",(0,r.yg)("inlineCode",{parentName:"p"},"TRUE")," or ",(0,r.yg)("inlineCode",{parentName:"p"},"FALSE"),":"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO user_active (username, is_active) VALUES\n ('user1', TRUE),\n ('user2', FALSE),\n ('user3', TRUE);\n")),(0,r.yg)("h2",{id:"querying-data-from-the-boolean-column"},"Querying data from the BOOLEAN column"),(0,r.yg)("p",null,"To query data from the BOOLEAN column, use standard SQL syntax:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT username, is_active FROM user_active;\n")),(0,r.yg)("p",null,"This query will return the following result:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre"},"username | is_active\n---------|----------\nuser1 | TRUE\nuser2 | FALSE\nuser3 | TRUE\n")),(0,r.yg)("h2",{id:"casting-between-boolean-and-integer"},"Casting between BOOLEAN and INTEGER"),(0,r.yg)("p",null,"You can cast between BOOLEAN and INTEGER values:"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"When casting a BOOLEAN to an INTEGER, ",(0,r.yg)("inlineCode",{parentName:"li"},"TRUE")," becomes ",(0,r.yg)("inlineCode",{parentName:"li"},"1")," and ",(0,r.yg)("inlineCode",{parentName:"li"},"FALSE")," becomes ",(0,r.yg)("inlineCode",{parentName:"li"},"0"),"."),(0,r.yg)("li",{parentName:"ul"},"When casting an INTEGER to a BOOLEAN, ",(0,r.yg)("inlineCode",{parentName:"li"},"1")," becomes ",(0,r.yg)("inlineCode",{parentName:"li"},"TRUE")," and ",(0,r.yg)("inlineCode",{parentName:"li"},"0")," becomes ",(0,r.yg)("inlineCode",{parentName:"li"},"FALSE"),". Other integer values will result in an error.")),(0,r.yg)("p",null,"Example:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT CAST(1 AS BOOLEAN); -- Result: TRUE\nSELECT CAST(0 AS BOOLEAN); -- Result: FALSE\nSELECT CAST(TRUE AS INTEGER); -- Result: 1\nSELECT CAST(FALSE AS INTEGER); -- Result: 0\n")),(0,r.yg)("p",null,"Note that casting negative integers or integers greater than 1 to BOOLEAN will result in an error."),(0,r.yg)("h2",{id:"conclusion"},"Conclusion"),(0,r.yg)("p",null,"In summary, the ",(0,r.yg)("inlineCode",{parentName:"p"},"BOOLEAN")," data type is a simple yet powerful way to represent binary states in SQL databases. With its ability to store ",(0,r.yg)("inlineCode",{parentName:"p"},"TRUE")," and ",(0,r.yg)("inlineCode",{parentName:"p"},"FALSE")," values, it can be used in various applications where binary conditions are necessary. Additionally, its compatibility with casting to and from INTEGER values provides added flexibility in data manipulation and querying. By understanding the basics of the BOOLEAN data type and its use cases, you can effectively use it in your database designs and operations."))}y.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/ebe12d94.e9202909.js b/docs/0.16.0/assets/js/ebe12d94.e9202909.js new file mode 100644 index 00000000..f2c47ea1 --- /dev/null +++ b/docs/0.16.0/assets/js/ebe12d94.e9202909.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[2025],{5680:(e,t,r)=>{r.d(t,{xA:()=>m,yg:()=>g});var n=r(6540);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function s(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?o(Object(r),!0).forEach((function(t){a(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):o(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function i(e,t){if(null==e)return{};var r,n,a=function(e,t){if(null==e)return{};var r,n,a={},o=Object.keys(e);for(n=0;n<o.length;n++)r=o[n],t.indexOf(r)>=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n<o.length;n++)r=o[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var l=n.createContext({}),p=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},m=function(e){var t=p(e.components);return n.createElement(l.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},c=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,l=e.parentName,m=i(e,["components","mdxType","originalType","parentName"]),u=p(r),c=a,g=u["".concat(l,".").concat(c)]||u[c]||d[c]||o;return r?n.createElement(g,s(s({ref:t},m),{},{components:r})):n.createElement(g,s({ref:t},m))}));function g(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,s=new Array(o);s[0]=c;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i[u]="string"==typeof e?e:a,s[1]=i;for(var p=2;p<o;p++)s[p]=r[p];return n.createElement.apply(null,s)}return n.createElement.apply(null,r)}c.displayName="MDXCreateElement"},6930:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>s,default:()=>d,frontMatter:()=>o,metadata:()=>i,toc:()=>p});var n=r(8168),a=(r(6540),r(5680));const o={sidebar_position:2},s="StoreMut",i={unversionedId:"storages/developing-custom-storages/store-traits/store-mut",id:"storages/developing-custom-storages/store-traits/store-mut",title:"StoreMut",description:"While the Store trait is for supporting SELECT queries and reading data, the StoreMut trait is for modifying data. Implementing the StoreMut trait requires the implementation of the Store trait as well. By implementing both the Store and StoreMut traits, you can support most of the commonly used SQL statements. Additionally, you can use the Test Suite to utilize the integration test set provided by GlueSQL. Custom storage developers can verify their own Store & StoreMut implementations by checking if they pass all the tests provided in the Test Suite.",source:"@site/docs/storages/developing-custom-storages/store-traits/store-mut.md",sourceDirName:"storages/developing-custom-storages/store-traits",slug:"/storages/developing-custom-storages/store-traits/store-mut",permalink:"/docs/0.16.0/storages/developing-custom-storages/store-traits/store-mut",draft:!1,tags:[],version:"current",sidebarPosition:2,frontMatter:{sidebar_position:2},sidebar:"autoSidebar",previous:{title:"Store",permalink:"/docs/0.16.0/storages/developing-custom-storages/store-traits/store"},next:{title:"AlterTable",permalink:"/docs/0.16.0/storages/developing-custom-storages/store-traits/alter-table"}},l={},p=[],m={toc:p},u="wrapper";function d(e){let{components:t,...r}=e;return(0,a.yg)(u,(0,n.A)({},m,r,{components:t,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"storemut"},"StoreMut"),(0,a.yg)("p",null,"While the ",(0,a.yg)("inlineCode",{parentName:"p"},"Store")," trait is for supporting SELECT queries and reading data, the ",(0,a.yg)("inlineCode",{parentName:"p"},"StoreMut")," trait is for modifying data. Implementing the ",(0,a.yg)("inlineCode",{parentName:"p"},"StoreMut")," trait requires the implementation of the ",(0,a.yg)("inlineCode",{parentName:"p"},"Store")," trait as well. By implementing both the ",(0,a.yg)("inlineCode",{parentName:"p"},"Store")," and ",(0,a.yg)("inlineCode",{parentName:"p"},"StoreMut")," traits, you can support most of the commonly used SQL statements. Additionally, you can use the Test Suite to utilize the integration test set provided by GlueSQL. Custom storage developers can verify their own Store & StoreMut implementations by checking if they pass all the tests provided in the Test Suite."),(0,a.yg)("p",null,"Here are the five methods required to implement the ",(0,a.yg)("inlineCode",{parentName:"p"},"StoreMut")," trait:"),(0,a.yg)("ol",null,(0,a.yg)("li",{parentName:"ol"},(0,a.yg)("p",{parentName:"li"},(0,a.yg)("inlineCode",{parentName:"p"},"insert_schema"),": This method is responsible for inserting a new schema into the storage system.")),(0,a.yg)("li",{parentName:"ol"},(0,a.yg)("p",{parentName:"li"},(0,a.yg)("inlineCode",{parentName:"p"},"delete_schema"),": This method is for deleting a schema from the storage system using the provided table name.")),(0,a.yg)("li",{parentName:"ol"},(0,a.yg)("p",{parentName:"li"},(0,a.yg)("inlineCode",{parentName:"p"},"append_data"),": This method appends a list of data rows to an existing table in the storage system.")),(0,a.yg)("li",{parentName:"ol"},(0,a.yg)("p",{parentName:"li"},(0,a.yg)("inlineCode",{parentName:"p"},"insert_data"),": This method inserts a list of key-data row pairs into an existing table in the storage system.")),(0,a.yg)("li",{parentName:"ol"},(0,a.yg)("p",{parentName:"li"},(0,a.yg)("inlineCode",{parentName:"p"},"delete_data"),": This method deletes a list of keys and their corresponding data rows from an existing table in the storage system."))),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-rust"},"/// By implementing `StoreMut` trait,\n/// you can run `INSERT`, `CREATE TABLE`, `DELETE`, `UPDATE` and `DROP TABLE` queries.\n#[async_trait(?Send)]\npub trait StoreMut {\n async fn insert_schema(&mut self, schema: &Schema) -> Result<()>;\n\n async fn delete_schema(&mut self, table_name: &str) -> Result<()>;\n\n async fn append_data(&mut self, table_name: &str, rows: Vec<DataRow>) -> Result<()>;\n\n async fn insert_data(&mut self, table_name: &str, rows: Vec<(Key, DataRow)>) -> Result<()>;\n\n async fn delete_data(&mut self, table_name: &str, keys: Vec<Key>) -> Result<()>;\n}\n")))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/ec040517.f0e83778.js b/docs/0.16.0/assets/js/ec040517.f0e83778.js new file mode 100644 index 00000000..ee4ba5e4 --- /dev/null +++ b/docs/0.16.0/assets/js/ec040517.f0e83778.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[7458],{6664:s=>{s.exports=JSON.parse('{"label":"sql","permalink":"/docs/0.16.0/blog/tags/sql","allTagsPath":"/docs/0.16.0/blog/tags","count":1}')}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/ec49082b.0c5dd593.js b/docs/0.16.0/assets/js/ec49082b.0c5dd593.js new file mode 100644 index 00000000..45c849af --- /dev/null +++ b/docs/0.16.0/assets/js/ec49082b.0c5dd593.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[306],{9354:a=>{a.exports=JSON.parse('{"label":"database","permalink":"/docs/0.16.0/blog/tags/database","allTagsPath":"/docs/0.16.0/blog/tags","count":3}')}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/eceb3b9b.bc074cbb.js b/docs/0.16.0/assets/js/eceb3b9b.bc074cbb.js new file mode 100644 index 00000000..9a4e6ec2 --- /dev/null +++ b/docs/0.16.0/assets/js/eceb3b9b.bc074cbb.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[7436],{5680:(e,n,t)=>{t.d(n,{xA:()=>c,yg:()=>y});var r=t(6540);function a(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function i(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function l(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?i(Object(t),!0).forEach((function(n){a(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):i(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function o(e,n){if(null==e)return{};var t,r,a=function(e,n){if(null==e)return{};var t,r,a={},i=Object.keys(e);for(r=0;r<i.length;r++)t=i[r],n.indexOf(t)>=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r<i.length;r++)t=i[r],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var s=r.createContext({}),p=function(e){var n=r.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):l(l({},n),e)),t},c=function(e){var n=p(e.components);return r.createElement(s.Provider,{value:n},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},g=r.forwardRef((function(e,n){var t=e.components,a=e.mdxType,i=e.originalType,s=e.parentName,c=o(e,["components","mdxType","originalType","parentName"]),u=p(t),g=a,y=u["".concat(s,".").concat(g)]||u[g]||m[g]||i;return t?r.createElement(y,l(l({ref:n},c),{},{components:t})):r.createElement(y,l({ref:n},c))}));function y(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var i=t.length,l=new Array(i);l[0]=g;var o={};for(var s in n)hasOwnProperty.call(n,s)&&(o[s]=n[s]);o.originalType=e,o[u]="string"==typeof e?e:a,l[1]=o;for(var p=2;p<i;p++)l[p]=t[p];return r.createElement.apply(null,l)}return r.createElement.apply(null,t)}g.displayName="MDXCreateElement"},457:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>s,contentTitle:()=>l,default:()=>m,frontMatter:()=>i,metadata:()=>o,toc:()=>p});var r=t(8168),a=(t(6540),t(5680));const i={},l="PI",o={unversionedId:"sql-syntax/functions/math/pi",id:"sql-syntax/functions/math/pi",title:"PI",description:"The PI function is used to retrieve the mathematical constant \u03c0 (pi), which is approximately 3.141592653589793. The function takes no arguments.",source:"@site/docs/sql-syntax/functions/math/pi.md",sourceDirName:"sql-syntax/functions/math",slug:"/sql-syntax/functions/math/pi",permalink:"/docs/0.16.0/sql-syntax/functions/math/pi",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"MOD",permalink:"/docs/0.16.0/sql-syntax/functions/math/mod"},next:{title:"POWER",permalink:"/docs/0.16.0/sql-syntax/functions/math/power"}},s={},p=[{value:"Syntax",id:"syntax",level:2},{value:"Examples",id:"examples",level:2},{value:"Example 1: Using PI function",id:"example-1-using-pi-function",level:3},{value:"Errors",id:"errors",level:2},{value:"Example 2: Using PI with an argument",id:"example-2-using-pi-with-an-argument",level:3}],c={toc:p},u="wrapper";function m(e){let{components:n,...t}=e;return(0,a.yg)(u,(0,r.A)({},c,t,{components:n,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"pi"},"PI"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"PI")," function is used to retrieve the mathematical constant \u03c0 (pi), which is approximately 3.141592653589793. The function takes no arguments."),(0,a.yg)("h2",{id:"syntax"},"Syntax"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"PI()\n")),(0,a.yg)("h2",{id:"examples"},"Examples"),(0,a.yg)("p",null,"Let's consider a table named ",(0,a.yg)("inlineCode",{parentName:"p"},"SingleItem")," with the following schema:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE SingleItem (id FLOAT);\n")),(0,a.yg)("p",null,"Insert a row into the ",(0,a.yg)("inlineCode",{parentName:"p"},"SingleItem")," table:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO SingleItem VALUES (0);\n")),(0,a.yg)("h3",{id:"example-1-using-pi-function"},"Example 1: Using PI function"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT PI() as pi FROM SingleItem;\n")),(0,a.yg)("p",null,"Result:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre"}," pi\n----------------\n3.141592653589793\n")),(0,a.yg)("h2",{id:"errors"},"Errors"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"PI")," function expects no arguments. Providing any arguments will result in an error."),(0,a.yg)("h3",{id:"example-2-using-pi-with-an-argument"},"Example 2: Using PI with an argument"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT PI(0) as pi FROM SingleItem;\n")),(0,a.yg)("p",null,"Error: Function expects 0 arguments, but 1 was provided."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/edb9b0b8.52075b0f.js b/docs/0.16.0/assets/js/edb9b0b8.52075b0f.js new file mode 100644 index 00000000..0122bc1b --- /dev/null +++ b/docs/0.16.0/assets/js/edb9b0b8.52075b0f.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[4467],{5680:(e,t,r)=>{r.d(t,{xA:()=>c,yg:()=>y});var n=r(6540);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function s(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?a(Object(r),!0).forEach((function(t){o(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):a(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function i(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},a=Object.keys(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=n.createContext({}),u=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},c=function(e){var t=u(e.components);return n.createElement(l.Provider,{value:t},e.children)},g="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,c=i(e,["components","mdxType","originalType","parentName"]),g=u(r),d=o,y=g["".concat(l,".").concat(d)]||g[d]||p[d]||a;return r?n.createElement(y,s(s({ref:t},c),{},{components:r})):n.createElement(y,s({ref:t},c))}));function y(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,s=new Array(a);s[0]=d;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i[g]="string"==typeof e?e:o,s[1]=i;for(var u=2;u<a;u++)s[u]=r[u];return n.createElement.apply(null,s)}return n.createElement.apply(null,r)}d.displayName="MDXCreateElement"},6539:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>s,default:()=>p,frontMatter:()=>a,metadata:()=>i,toc:()=>u});var n=r(8168),o=(r(6540),r(5680));const a={},s="WebStorage (local & session)",i={unversionedId:"storages/supported-storages/web-storage",id:"storages/supported-storages/web-storage",title:"WebStorage (local & session)",description:"WebStorage - yes, the localStorage and sessionStorage you're familiar with. With GlueSQL, you can use SQL to interact with these storages!",source:"@site/docs/storages/supported-storages/web-storage.md",sourceDirName:"storages/supported-storages",slug:"/storages/supported-storages/web-storage",permalink:"/docs/0.16.0/storages/supported-storages/web-storage",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"Sled Storage",permalink:"/docs/0.16.0/storages/supported-storages/sled-storage"},next:{title:"Introduction",permalink:"/docs/0.16.0/storages/developing-custom-storages/intro"}},l={},u=[{value:"Usage",id:"usage",level:2},{value:"Things to keep in mind",id:"things-to-keep-in-mind",level:2},{value:"Summary",id:"summary",level:2}],c={toc:u},g="wrapper";function p(e){let{components:t,...r}=e;return(0,o.yg)(g,(0,n.A)({},c,r,{components:t,mdxType:"MDXLayout"}),(0,o.yg)("h1",{id:"webstorage-local--session"},"WebStorage (local & session)"),(0,o.yg)("p",null,"WebStorage - yes, the localStorage and sessionStorage you're familiar with. With GlueSQL, you can use SQL to interact with these storages!"),(0,o.yg)("p",null,"WebStorage serves as a data storage that supports READ & WRITE operations. As GlueSQL can be ported to any place where READ & WRITE are possible, it can utilize WebStorage as one of its storage systems."),(0,o.yg)("p",null,"WebStorage provides a very simple and easy-to-use interface. All you need to do is read and write data using a string key. If you need to manage more structured data, you can use GlueSQL."),(0,o.yg)("p",null,"WebStorage can be used in JavaScript (Web) environments and Rust WebAssembly environments."),(0,o.yg)("h2",{id:"usage"},"Usage"),(0,o.yg)("p",null,"The way to use it is no different from using other storages."),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-javascript"},"import { gluesql } from 'gluesql';\n\nasync function run() {\n const db = await gluesql();\n\n const result = await db.query(`\n CREATE TABLE Foo (id INTEGER, name TEXT) ENGINE = localStorage;\n INSERT INTO Foo VALUES (1, 'hello'), (2, 'world');\n SELECT * FROM Foo;\n CREATE TABLE Bar ENGINE = sessionStorage;\n INSERT INTO Bar VALUES ('{ \"a\": \"schemaless\", \"b\": 1024 }');\n SELECT * FROM Bar;\n `);\n\n console.log(result);\n}\n")),(0,o.yg)("p",null,"Simple, isn't it?"),(0,o.yg)("h2",{id:"things-to-keep-in-mind"},"Things to keep in mind"),(0,o.yg)("p",null,"In the case of WebStorage, depending on the web browser, there is usually a size constraint of about 10MB for data storage. Even when using GlueSQL, you should keep in mind that it is used within these restrictions."),(0,o.yg)("h2",{id:"summary"},"Summary"),(0,o.yg)("p",null,"To sum up, WebStorage is a handy feature that allows you to manipulate localStorage and sessionStorage with SQL in a browser environment. It's simple, easy to use, and can handle structured data which makes it an ideal choice for lightweight web applications."),(0,o.yg)("p",null,"However, due to storage limitations, it's not suitable for large-scale data handling. Remember to consider these limitations when choosing your storage options in GlueSQL. Even with these constraints, it serves as a great tool for managing and interacting with your browser's storage in a structured way using SQL."))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/ee244d12.81f504bd.js b/docs/0.16.0/assets/js/ee244d12.81f504bd.js new file mode 100644 index 00000000..2e4e9fc6 --- /dev/null +++ b/docs/0.16.0/assets/js/ee244d12.81f504bd.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[1226],{5680:(e,t,n)=>{n.d(t,{xA:()=>u,yg:()=>y});var r=n(6540);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},i=Object.keys(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var g=r.createContext({}),s=function(e){var t=r.useContext(g),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},u=function(e){var t=s(e.components);return r.createElement(g.Provider,{value:t},e.children)},c="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,g=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),c=s(n),d=a,y=c["".concat(g,".").concat(d)]||c[d]||p[d]||i;return n?r.createElement(y,o(o({ref:t},u),{},{components:n})):r.createElement(y,o({ref:t},u))}));function y(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,o=new Array(i);o[0]=d;var l={};for(var g in t)hasOwnProperty.call(t,g)&&(l[g]=t[g]);l.originalType=e,l[c]="string"==typeof e?e:a,o[1]=l;for(var s=2;s<i;s++)o[s]=n[s];return r.createElement.apply(null,o)}return r.createElement.apply(null,n)}d.displayName="MDXCreateElement"},2853:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>g,contentTitle:()=>o,default:()=>p,frontMatter:()=>i,metadata:()=>l,toc:()=>s});var r=n(8168),a=(n(6540),n(5680));const i={sidebar_position:1},o="Fetching Data from Storage",l={unversionedId:"ast-builder/statements/querying/fetching-data-from-storage",id:"ast-builder/statements/querying/fetching-data-from-storage",title:"Fetching Data from Storage",description:"The AST Builder provides a powerful and flexible way to query data from your tables, similar to SQL's SELECT statement. This guide will show you how to use the AST Builder's table(\"foo\").select() method to perform various query types, including filtering, joining, grouping, ordering, and pagination.",source:"@site/docs/ast-builder/statements/querying/fetching-data-from-storage.md",sourceDirName:"ast-builder/statements/querying",slug:"/ast-builder/statements/querying/fetching-data-from-storage",permalink:"/docs/0.16.0/ast-builder/statements/querying/fetching-data-from-storage",draft:!1,tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"autoSidebar",previous:{title:"Introduction",permalink:"/docs/0.16.0/ast-builder/intro"},next:{title:"Using Preloaded Data",permalink:"/docs/0.16.0/ast-builder/statements/querying/using-preloaded-data"}},g={},s=[{value:"Basic SELECT",id:"basic-select",level:2},{value:"Filtering (WHERE)",id:"filtering-where",level:2},{value:"Joining Tables",id:"joining-tables",level:2},{value:"Grouping and Aggregating (GROUP BY, HAVING)",id:"grouping-and-aggregating-group-by-having",level:2},{value:"Sorting Results (ORDER BY)",id:"sorting-results-order-by",level:2},{value:"Pagination (OFFSET, LIMIT)",id:"pagination-offset-limit",level:2}],u={toc:s},c="wrapper";function p(e){let{components:t,...n}=e;return(0,a.yg)(c,(0,r.A)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"fetching-data-from-storage"},"Fetching Data from Storage"),(0,a.yg)("p",null,"The AST Builder provides a powerful and flexible way to query data from your tables, similar to SQL's SELECT statement. This guide will show you how to use the AST Builder's ",(0,a.yg)("inlineCode",{parentName:"p"},'table("foo").select()')," method to perform various query types, including filtering, joining, grouping, ordering, and pagination."),(0,a.yg)("h2",{id:"basic-select"},"Basic SELECT"),(0,a.yg)("p",null,"To perform a basic SELECT query using the AST Builder, simply call the ",(0,a.yg)("inlineCode",{parentName:"p"},"select()")," method on a table object."),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Category").select().execute(glue).await;\n')),(0,a.yg)("h2",{id:"filtering-where"},"Filtering (WHERE)"),(0,a.yg)("p",null,"To filter the results of a SELECT query, use the ",(0,a.yg)("inlineCode",{parentName:"p"},"filter()")," method, providing a condition as a string."),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Category")\n .select()\n .filter("name = \'Meat\'")\n .execute(glue)\n .await;\n')),(0,a.yg)("h2",{id:"joining-tables"},"Joining Tables"),(0,a.yg)("p",null,"You can join tables using the ",(0,a.yg)("inlineCode",{parentName:"p"},"join()")," or ",(0,a.yg)("inlineCode",{parentName:"p"},"join_as()")," methods. The following example demonstrates an INNER JOIN:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Item")\n .alias_as("i")\n .select()\n .join_as("Category", "c")\n .on("c.id = i.category_id")\n .filter("c.name = \'Fruit\' OR c.name = \'Meat\'")\n .project("i.name AS item")\n .project("c.name AS category")\n .execute(glue)\n .await;\n')),(0,a.yg)("p",null,"For LEFT OUTER JOIN, use the ",(0,a.yg)("inlineCode",{parentName:"p"},"left_join()")," method:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Category")\n .select()\n .left_join("Item")\n .on(col("Category.id")\n .eq(col("Item.category_id"))\n .and(col("price").gt(50)))\n .project(vec![\n "Category.name AS category",\n "Item.name AS item",\n "price",\n ])\n .execute(glue)\n .await;\n')),(0,a.yg)("h2",{id:"grouping-and-aggregating-group-by-having"},"Grouping and Aggregating (GROUP BY, HAVING)"),(0,a.yg)("p",null,"To group the results of a SELECT query, use the ",(0,a.yg)("inlineCode",{parentName:"p"},"group_by()")," method. You can also filter the groups using the ",(0,a.yg)("inlineCode",{parentName:"p"},"having()")," method."),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Item")\n .select()\n .join("Category")\n .on(col("Category.id").eq("Item.category_id"))\n .group_by("Item.category_id")\n .having("SUM(Item.price) > 80")\n .project("Category.name AS category")\n .project("SUM(Item.price) AS sum_price")\n .execute(glue)\n .await;\n')),(0,a.yg)("h2",{id:"sorting-results-order-by"},"Sorting Results (ORDER BY)"),(0,a.yg)("p",null,"To sort the results of a SELECT query, use the ",(0,a.yg)("inlineCode",{parentName:"p"},"order_by()")," method."),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Item")\n .select()\n .project("name, price")\n .order_by("price DESC")\n .execute(glue)\n .await;\n')),(0,a.yg)("h2",{id:"pagination-offset-limit"},"Pagination (OFFSET, LIMIT)"),(0,a.yg)("p",null,"You can paginate the results of a SELECT query using the ",(0,a.yg)("inlineCode",{parentName:"p"},"offset()")," and ",(0,a.yg)("inlineCode",{parentName:"p"},"limit()")," methods."),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-rust"},'let actual = table("Item")\n .select()\n .project("name, price")\n .order_by("price DESC")\n .offset(1)\n .limit(2)\n .execute(glue)\n .await;\n')))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/f11e9837.fbbfe220.js b/docs/0.16.0/assets/js/f11e9837.fbbfe220.js new file mode 100644 index 00000000..eafcf226 --- /dev/null +++ b/docs/0.16.0/assets/js/f11e9837.fbbfe220.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[1007],{4871:s=>{s.exports=JSON.parse('{"label":"v0.15","permalink":"/docs/0.16.0/blog/tags/v-0-15","allTagsPath":"/docs/0.16.0/blog/tags","count":1}')}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/f1257df2.c27413b8.js b/docs/0.16.0/assets/js/f1257df2.c27413b8.js new file mode 100644 index 00000000..521de803 --- /dev/null +++ b/docs/0.16.0/assets/js/f1257df2.c27413b8.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[7278],{5680:(e,t,n)=>{n.d(t,{xA:()=>c,yg:()=>f});var r=n(6540);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function l(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?a(Object(n),!0).forEach((function(t){o(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):a(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function i(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},a=Object.keys(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=r.createContext({}),u=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},c=function(e){var t=u(e.components);return r.createElement(s.Provider,{value:t},e.children)},p="mdxType",g={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,s=e.parentName,c=i(e,["components","mdxType","originalType","parentName"]),p=u(n),m=o,f=p["".concat(s,".").concat(m)]||p[m]||g[m]||a;return n?r.createElement(f,l(l({ref:t},c),{},{components:n})):r.createElement(f,l({ref:t},c))}));function f(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,l=new Array(a);l[0]=m;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i[p]="string"==typeof e?e:o,l[1]=i;for(var u=2;u<a;u++)l[u]=n[u];return r.createElement.apply(null,l)}return r.createElement.apply(null,n)}m.displayName="MDXCreateElement"},1626:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>g,frontMatter:()=>a,metadata:()=>i,toc:()=>u});var r=n(8168),o=(n(6540),n(5680));const a={},l="LOG2",i={unversionedId:"sql-syntax/functions/math/log2",id:"sql-syntax/functions/math/log2",title:"LOG2",description:"The LOG2 function is used to calculate the base-2 logarithm of a number. It takes a single FLOAT or INTEGER argument and returns a FLOAT value representing the base-2 logarithm of the given number.",source:"@site/docs/sql-syntax/functions/math/log2.md",sourceDirName:"sql-syntax/functions/math",slug:"/sql-syntax/functions/math/log2",permalink:"/docs/0.16.0/sql-syntax/functions/math/log2",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"LOG10",permalink:"/docs/0.16.0/sql-syntax/functions/math/log10"},next:{title:"MOD",permalink:"/docs/0.16.0/sql-syntax/functions/math/mod"}},s={},u=[{value:"Example",id:"example",level:2},{value:"Errors",id:"errors",level:2}],c={toc:u},p="wrapper";function g(e){let{components:t,...n}=e;return(0,o.yg)(p,(0,r.A)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,o.yg)("h1",{id:"log2"},"LOG2"),(0,o.yg)("p",null,"The ",(0,o.yg)("inlineCode",{parentName:"p"},"LOG2")," function is used to calculate the base-2 logarithm of a number. It takes a single FLOAT or INTEGER argument and returns a FLOAT value representing the base-2 logarithm of the given number."),(0,o.yg)("h2",{id:"example"},"Example"),(0,o.yg)("p",null,"The following example demonstrates the usage of the ",(0,o.yg)("inlineCode",{parentName:"p"},"LOG2")," function in a SQL query:"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE SingleItem (id INTEGER DEFAULT LOG2(1024));\n\nINSERT INTO SingleItem VALUES (0);\n\nSELECT\n LOG2(64.0) as log2_1,\n LOG2(0.04) as log2_2\nFROM SingleItem;\n")),(0,o.yg)("p",null,"This will return the following result:"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre"},"log2_1 | log2_2\n-------+-------------------\n6.0 | -4.5850\n")),(0,o.yg)("h2",{id:"errors"},"Errors"),(0,o.yg)("ol",null,(0,o.yg)("li",{parentName:"ol"},"If the argument is not of FLOAT or INTEGER type, a ",(0,o.yg)("inlineCode",{parentName:"li"},"FunctionRequiresFloatValue")," error will be raised."),(0,o.yg)("li",{parentName:"ol"},"If the number of arguments provided to the function is not equal to 1, a ",(0,o.yg)("inlineCode",{parentName:"li"},"FunctionArgsLengthNotMatching")," error will be raised.")))}g.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/f18bbaf6.3a12296c.js b/docs/0.16.0/assets/js/f18bbaf6.3a12296c.js new file mode 100644 index 00000000..cdcc0da7 --- /dev/null +++ b/docs/0.16.0/assets/js/f18bbaf6.3a12296c.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[1485],{5680:(e,t,a)=>{a.d(t,{xA:()=>m,yg:()=>g});var n=a(6540);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function i(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function o(e){for(var t=1;t<arguments.length;t++){var a=null!=arguments[t]?arguments[t]:{};t%2?i(Object(a),!0).forEach((function(t){r(e,t,a[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(a)):i(Object(a)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(a,t))}))}return e}function l(e,t){if(null==e)return{};var a,n,r=function(e,t){if(null==e)return{};var a,n,r={},i=Object.keys(e);for(n=0;n<i.length;n++)a=i[n],t.indexOf(a)>=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)a=i[n],t.indexOf(a)>=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var p=n.createContext({}),s=function(e){var t=n.useContext(p),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},m=function(e){var t=s(e.components);return n.createElement(p.Provider,{value:t},e.children)},u="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},y=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,i=e.originalType,p=e.parentName,m=l(e,["components","mdxType","originalType","parentName"]),u=s(a),y=r,g=u["".concat(p,".").concat(y)]||u[y]||c[y]||i;return a?n.createElement(g,o(o({ref:t},m),{},{components:a})):n.createElement(g,o({ref:t},m))}));function g(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=a.length,o=new Array(i);o[0]=y;var l={};for(var p in t)hasOwnProperty.call(t,p)&&(l[p]=t[p]);l.originalType=e,l[u]="string"==typeof e?e:r,o[1]=l;for(var s=2;s<i;s++)o[s]=a[s];return n.createElement.apply(null,o)}return n.createElement.apply(null,a)}y.displayName="MDXCreateElement"},8072:(e,t,a)=>{a.r(t),a.d(t,{assets:()=>p,contentTitle:()=>o,default:()=>c,frontMatter:()=>i,metadata:()=>l,toc:()=>s});var n=a(8168),r=(a(6540),a(5680));const i={},o="FORMAT",l={unversionedId:"sql-syntax/functions/datetime/format",id:"sql-syntax/functions/datetime/format",title:"FORMAT",description:"The FORMAT function in SQL is used to format date, time, and timestamp values into a specified format.",source:"@site/docs/sql-syntax/functions/datetime/format.md",sourceDirName:"sql-syntax/functions/datetime",slug:"/sql-syntax/functions/datetime/format",permalink:"/docs/0.16.0/sql-syntax/functions/datetime/format",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"EXTRACT",permalink:"/docs/0.16.0/sql-syntax/functions/datetime/extract"},next:{title:"NOW",permalink:"/docs/0.16.0/sql-syntax/functions/datetime/now"}},p={},s=[{value:"Syntax",id:"syntax",level:2},{value:"Usage",id:"usage",level:2},{value:"Error Example",id:"error-example",level:2}],m={toc:s},u="wrapper";function c(e){let{components:t,...a}=e;return(0,r.yg)(u,(0,n.A)({},m,a,{components:t,mdxType:"MDXLayout"}),(0,r.yg)("h1",{id:"format"},"FORMAT"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"FORMAT")," function in SQL is used to format date, time, and timestamp values into a specified format."),(0,r.yg)("h2",{id:"syntax"},"Syntax"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"FORMAT(value, format)\n")),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"value"),": The date, time, or timestamp value that is to be formatted."),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("inlineCode",{parentName:"li"},"format"),": The format in which the value is to be displayed. This is a string that contains format specifiers, such as ",(0,r.yg)("inlineCode",{parentName:"li"},"%Y")," for four-digit year, ",(0,r.yg)("inlineCode",{parentName:"li"},"%m")," for two-digit month, and so on.")),(0,r.yg)("h2",{id:"usage"},"Usage"),(0,r.yg)("p",null,"Here are examples of how ",(0,r.yg)("inlineCode",{parentName:"p"},"FORMAT")," can be used to display datetime components in various formats:"),(0,r.yg)("ol",null,(0,r.yg)("li",{parentName:"ol"},(0,r.yg)("p",{parentName:"li"},"Formatting a ",(0,r.yg)("inlineCode",{parentName:"p"},"DATE")," value: "),(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT FORMAT(DATE '2017-06-15','%Y-%m') AS date;\n")),(0,r.yg)("p",{parentName:"li"},"This returns ",(0,r.yg)("inlineCode",{parentName:"p"},'"2017-06"'),".")),(0,r.yg)("li",{parentName:"ol"},(0,r.yg)("p",{parentName:"li"},"Formatting a ",(0,r.yg)("inlineCode",{parentName:"p"},"TIMESTAMP")," value: "),(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT FORMAT(TIMESTAMP '2015-09-05 23:56:04', '%Y-%m-%d %H:%M:%S') AS timestamp;\n")),(0,r.yg)("p",{parentName:"li"},"This returns ",(0,r.yg)("inlineCode",{parentName:"p"},'"2015-09-05 23:56:04"'),".")),(0,r.yg)("li",{parentName:"ol"},(0,r.yg)("p",{parentName:"li"},"Formatting a ",(0,r.yg)("inlineCode",{parentName:"p"},"TIME")," value: "),(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT FORMAT(TIME '23:56:04','%H:%M') AS time;\n")),(0,r.yg)("p",{parentName:"li"},"This returns ",(0,r.yg)("inlineCode",{parentName:"p"},'"23:56"'),".")),(0,r.yg)("li",{parentName:"ol"},(0,r.yg)("p",{parentName:"li"},"Formatting different components of a ",(0,r.yg)("inlineCode",{parentName:"p"},"TIMESTAMP")," value separately: "),(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT \n FORMAT(TIMESTAMP '2015-09-05 23:56:04', '%Y') AS year,\n FORMAT(TIMESTAMP '2015-09-05 23:56:04', '%m') AS month,\n FORMAT(TIMESTAMP '2015-09-05 23:56:04', '%d') AS day;\n")),(0,r.yg)("p",{parentName:"li"},"This returns:"),(0,r.yg)("pre",{parentName:"li"},(0,r.yg)("code",{parentName:"pre"},"year | month | day\n-----+-------+-----\n2015 | 09 | 05\n")))),(0,r.yg)("p",null,"Please note that the ",(0,r.yg)("inlineCode",{parentName:"p"},"FORMAT")," function only accepts date, time, or timestamp values. If you try to format a value with an incorrect type, you will encounter an error."),(0,r.yg)("h2",{id:"error-example"},"Error Example"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT FORMAT('2015-09-05 23:56:04', '%Y-%m-%d %H') AS timestamp;\n")),(0,r.yg)("p",null,"This will throw an error because the input value is a string, not a date, time, or timestamp value:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-rust"},'EvaluateError::UnsupportedExprForFormatFunction("2015-09-05 23:56:04".to_owned())\n')))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/f33f2c05.bece9048.js b/docs/0.16.0/assets/js/f33f2c05.bece9048.js new file mode 100644 index 00000000..710d76df --- /dev/null +++ b/docs/0.16.0/assets/js/f33f2c05.bece9048.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[7309],{5680:(e,t,n)=>{n.d(t,{xA:()=>c,yg:()=>g});var a=n(6540);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,a,r=function(e,t){if(null==e)return{};var n,a,r={},o=Object.keys(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=a.createContext({}),u=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},c=function(e){var t=u(e.components);return a.createElement(s.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},y=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,s=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),p=u(n),y=r,g=p["".concat(s,".").concat(y)]||p[y]||d[y]||o;return n?a.createElement(g,i(i({ref:t},c),{},{components:n})):a.createElement(g,i({ref:t},c))}));function g(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=y;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[p]="string"==typeof e?e:r,i[1]=l;for(var u=2;u<o;u++)i[u]=n[u];return a.createElement.apply(null,i)}return a.createElement.apply(null,n)}y.displayName="MDXCreateElement"},6794:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>d,frontMatter:()=>o,metadata:()=>l,toc:()=>u});var a=n(8168),r=(n(6540),n(5680));const o={sidebar_position:3},i="FLOAT",l={unversionedId:"sql-syntax/data-types/float",id:"sql-syntax/data-types/float",title:"FLOAT",description:"The FLOAT data type in SQL is used to store floating-point numbers. In GlueSQL, the FLOAT data type represents a 64-bit floating-point number, providing the ability to store numbers with decimal values and a wide range of magnitude.",source:"@site/docs/sql-syntax/data-types/float.md",sourceDirName:"sql-syntax/data-types",slug:"/sql-syntax/data-types/float",permalink:"/docs/0.16.0/sql-syntax/data-types/float",draft:!1,tags:[],version:"current",sidebarPosition:3,frontMatter:{sidebar_position:3},sidebar:"autoSidebar",previous:{title:"Integer Types",permalink:"/docs/0.16.0/sql-syntax/data-types/integers"},next:{title:"TEXT",permalink:"/docs/0.16.0/sql-syntax/data-types/text"}},s={},u=[{value:"Creating a table with a FLOAT column",id:"creating-a-table-with-a-float-column",level:2},{value:"Inserting data into the FLOAT column",id:"inserting-data-into-the-float-column",level:2},{value:"Querying data from the FLOAT column",id:"querying-data-from-the-float-column",level:2},{value:"Conclusion",id:"conclusion",level:2}],c={toc:u},p="wrapper";function d(e){let{components:t,...n}=e;return(0,r.yg)(p,(0,a.A)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,r.yg)("h1",{id:"float"},"FLOAT"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"FLOAT")," data type in SQL is used to store floating-point numbers. In GlueSQL, the FLOAT data type represents a 64-bit floating-point number, providing the ability to store numbers with decimal values and a wide range of magnitude."),(0,r.yg)("p",null,"Here's an example of how to create a table, insert data, and query data using the ",(0,r.yg)("inlineCode",{parentName:"p"},"FLOAT")," data type:"),(0,r.yg)("h2",{id:"creating-a-table-with-a-float-column"},"Creating a table with a FLOAT column"),(0,r.yg)("p",null,"To create a table with a FLOAT column, use the following SQL syntax:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE product_prices (product_name TEXT, price FLOAT);\n")),(0,r.yg)("h2",{id:"inserting-data-into-the-float-column"},"Inserting data into the FLOAT column"),(0,r.yg)("p",null,"To insert data into the FLOAT column, provide the floating-point values:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO product_prices (product_name, price) VALUES\n ('Product A', 19.99),\n ('Product B', 39.49),\n ('Product C', 12.75);\n")),(0,r.yg)("h2",{id:"querying-data-from-the-float-column"},"Querying data from the FLOAT column"),(0,r.yg)("p",null,"To query data from the FLOAT column, use standard SQL syntax:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT product_name, price FROM product_prices;\n")),(0,r.yg)("p",null,"This query will return the following result:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre"},"product_name | price\n-------------|-------\nProduct A | 19.99\nProduct B | 39.49\nProduct C | 12.75\n")),(0,r.yg)("h2",{id:"conclusion"},"Conclusion"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"FLOAT")," data type is essential for handling numeric data with decimal values and various magnitudes. By understanding the basics of the FLOAT data type and its use cases, you can effectively use it in your database designs and operations, ensuring that your applications can handle a wide range of numerical values with precision."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/f6ca3de5.1be337f5.js b/docs/0.16.0/assets/js/f6ca3de5.1be337f5.js new file mode 100644 index 00000000..469acc84 --- /dev/null +++ b/docs/0.16.0/assets/js/f6ca3de5.1be337f5.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[7532],{5680:(e,t,r)=>{r.d(t,{xA:()=>s,yg:()=>y});var n=r(6540);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?a(Object(r),!0).forEach((function(t){o(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):a(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function c(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},a=Object.keys(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=n.createContext({}),u=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},s=function(e){var t=u(e.components);return n.createElement(l.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},f=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,s=c(e,["components","mdxType","originalType","parentName"]),p=u(r),f=o,y=p["".concat(l,".").concat(f)]||p[f]||d[f]||a;return r?n.createElement(y,i(i({ref:t},s),{},{components:r})):n.createElement(y,i({ref:t},s))}));function y(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,i=new Array(a);i[0]=f;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c[p]="string"==typeof e?e:o,i[1]=c;for(var u=2;u<a;u++)i[u]=r[u];return n.createElement.apply(null,i)}return n.createElement.apply(null,r)}f.displayName="MDXCreateElement"},1046:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>d,frontMatter:()=>a,metadata:()=>c,toc:()=>u});var n=r(8168),o=(r(6540),r(5680));const a={},i="Coordinate Extraction",c={unversionedId:"ast-builder/functions/geometry/coordinate-extraction",id:"ast-builder/functions/geometry/coordinate-extraction",title:"Coordinate Extraction",description:"Todo",source:"@site/docs/ast-builder/functions/geometry/coordinate-extraction.md",sourceDirName:"ast-builder/functions/geometry",slug:"/ast-builder/functions/geometry/coordinate-extraction",permalink:"/docs/0.16.0/ast-builder/functions/geometry/coordinate-extraction",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"List Manipulation",permalink:"/docs/0.16.0/ast-builder/functions/list-&-map/list-manipulation"},next:{title:"Distance Calculation",permalink:"/docs/0.16.0/ast-builder/functions/geometry/distance-calculation"}},l={},u=[{value:"Todo",id:"todo",level:2}],s={toc:u},p="wrapper";function d(e){let{components:t,...r}=e;return(0,o.yg)(p,(0,n.A)({},s,r,{components:t,mdxType:"MDXLayout"}),(0,o.yg)("h1",{id:"coordinate-extraction"},"Coordinate Extraction"),(0,o.yg)("h2",{id:"todo"},"Todo"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre"},"- GET_X: Extracts the x-coordinate from a point.\n- GET_Y: Extracts the y-coordinate from a point.\n")))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/f7912ff8.139c630a.js b/docs/0.16.0/assets/js/f7912ff8.139c630a.js new file mode 100644 index 00000000..21d4c25e --- /dev/null +++ b/docs/0.16.0/assets/js/f7912ff8.139c630a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[6834],{5680:(e,a,t)=>{t.d(a,{xA:()=>g,yg:()=>m});var n=t(6540);function r(e,a,t){return a in e?Object.defineProperty(e,a,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[a]=t,e}function i(e,a){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);a&&(n=n.filter((function(a){return Object.getOwnPropertyDescriptor(e,a).enumerable}))),t.push.apply(t,n)}return t}function s(e){for(var a=1;a<arguments.length;a++){var t=null!=arguments[a]?arguments[a]:{};a%2?i(Object(t),!0).forEach((function(a){r(e,a,t[a])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):i(Object(t)).forEach((function(a){Object.defineProperty(e,a,Object.getOwnPropertyDescriptor(t,a))}))}return e}function l(e,a){if(null==e)return{};var t,n,r=function(e,a){if(null==e)return{};var t,n,r={},i=Object.keys(e);for(n=0;n<i.length;n++)t=i[n],a.indexOf(t)>=0||(r[t]=e[t]);return r}(e,a);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)t=i[n],a.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var o=n.createContext({}),u=function(e){var a=n.useContext(o),t=a;return e&&(t="function"==typeof e?e(a):s(s({},a),e)),t},g=function(e){var a=u(e.components);return n.createElement(o.Provider,{value:a},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var a=e.children;return n.createElement(n.Fragment,{},a)}},c=n.forwardRef((function(e,a){var t=e.components,r=e.mdxType,i=e.originalType,o=e.parentName,g=l(e,["components","mdxType","originalType","parentName"]),p=u(t),c=r,m=p["".concat(o,".").concat(c)]||p[c]||d[c]||i;return t?n.createElement(m,s(s({ref:a},g),{},{components:t})):n.createElement(m,s({ref:a},g))}));function m(e,a){var t=arguments,r=a&&a.mdxType;if("string"==typeof e||r){var i=t.length,s=new Array(i);s[0]=c;var l={};for(var o in a)hasOwnProperty.call(a,o)&&(l[o]=a[o]);l.originalType=e,l[p]="string"==typeof e?e:r,s[1]=l;for(var u=2;u<i;u++)s[u]=t[u];return n.createElement.apply(null,s)}return n.createElement.apply(null,t)}c.displayName="MDXCreateElement"},2673:(e,a,t)=>{t.r(a),t.d(a,{assets:()=>o,contentTitle:()=>s,default:()=>d,frontMatter:()=>i,metadata:()=>l,toc:()=>u});var n=t(8168),r=(t(6540),t(5680));const i={},s="Parquet Storage",l={unversionedId:"storages/supported-storages/parquet-storage",id:"storages/supported-storages/parquet-storage",title:"Parquet Storage",description:"Introduction",source:"@site/docs/storages/supported-storages/parquet-storage.md",sourceDirName:"storages/supported-storages",slug:"/storages/supported-storages/parquet-storage",permalink:"/docs/0.16.0/storages/supported-storages/parquet-storage",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"Memory Storage",permalink:"/docs/0.16.0/storages/supported-storages/memory-storage"},next:{title:"Shared Memory Storage",permalink:"/docs/0.16.0/storages/supported-storages/shared-memory-storage"}},o={},u=[{value:"Introduction",id:"introduction",level:2},{value:"Structure",id:"structure",level:2},{value:"Schema File",id:"schema-file",level:2},{value:"Examples",id:"examples",level:3},{value:"Creating a Table",id:"creating-a-table",level:4},{value:"Inserting Data and Querying",id:"inserting-data-and-querying",level:4},{value:"Updating Data and Querying",id:"updating-data-and-querying",level:4},{value:"Deleting Data and Querying",id:"deleting-data-and-querying",level:4},{value:"Schemaless File Interaction",id:"schemaless-file-interaction",level:2},{value:"Implications",id:"implications",level:3},{value:"Examples",id:"examples-1",level:3},{value:"Creating Schemaless Table, Inserting, and Querying Data",id:"creating-schemaless-table-inserting-and-querying-data",level:4},{value:"Updating Data and Querying",id:"updating-data-and-querying-1",level:4},{value:"Deleting Data and Querying",id:"deleting-data-and-querying-1",level:4},{value:"Limitations",id:"limitations",level:2},{value:"Conclusion",id:"conclusion",level:2}],g={toc:u},p="wrapper";function d(e){let{components:a,...t}=e;return(0,r.yg)(p,(0,n.A)({},g,t,{components:a,mdxType:"MDXLayout"}),(0,r.yg)("h1",{id:"parquet-storage"},"Parquet Storage"),(0,r.yg)("h2",{id:"introduction"},"Introduction"),(0,r.yg)("p",null,"The Parquet Storage Extension empowers users to interact with Parquet files through SQL statements efficiently, making the reading and writing of Parquet files straightforward and user-friendly."),(0,r.yg)("h2",{id:"structure"},"Structure"),(0,r.yg)("p",null,"The extension is designed to handle files with a ",(0,r.yg)("inlineCode",{parentName:"p"},".parquet")," extension and performs read and write operations in the path specified by the user. It provides flexibility for creating files with or without a predefined schema using the DDL statement, adjusting to user needs effectively."),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},(0,r.yg)("strong",{parentName:"p"},"Schema or Schema-less Files Creation:"),"\nUsers can create either schema or schema-less files using the table name defined in the DDL statement. It adjusts the Parquet's schema and field information to align with GlueSQL's constructs, enabling efficient data querying processes.")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},(0,r.yg)("strong",{parentName:"p"},"Data Querying:"),"\nWhen querying data, the extension converts Parquet's schema and field information to GlueSQL's corresponding constructs. This conversion allows users to perform data queries seamlessly, leveraging the uniformity in schema and field information representation.")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},(0,r.yg)("strong",{parentName:"p"},"Data Modification:"),"\nAny changes in the data are reverted from GlueSQL's schema and field information back to Parquet's original constructs before being written back to a ",(0,r.yg)("inlineCode",{parentName:"p"},".parquet")," file. This bidirectional conversion ensures data integrity and consistency between the two formats during read and write operations."))),(0,r.yg)("h2",{id:"schema-file"},"Schema File"),(0,r.yg)("p",null,"With this extension, you can create new schemas using DDL statements and modify data using DML statements, ensuring seamless interaction with Parquet files."),(0,r.yg)("h3",{id:"examples"},"Examples"),(0,r.yg)("blockquote",null,(0,r.yg)("p",{parentName:"blockquote"},(0,r.yg)("strong",{parentName:"p"},"Note:")," ",(0,r.yg)("inlineCode",{parentName:"p"},"{}")," denotes a placeholder that you must replace with actual values.")),(0,r.yg)("p",null,"To start interacting with the Parquet extension, use the following command in your CLI:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sh"},"./gluesql -p {workspace path} -s parquet\n")),(0,r.yg)("h4",{id:"creating-a-table"},"Creating a Table"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"gluesql> CREATE TABLE food (name TEXT);\n")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"Table created\n")),(0,r.yg)("p",null,"At this point, you can verify the creation of the food.parquet file in the specified path (./)."),(0,r.yg)("h4",{id:"inserting-data-and-querying"},"Inserting Data and Querying"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO food VALUES('sushi'), ('steak');\n\nSELECT * FROM food;\n")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"2 row inserted\n\n| name |\n|-------|\n| sushi |\n| steak |\n")),(0,r.yg)("h4",{id:"updating-data-and-querying"},"Updating Data and Querying"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"UPDATE food SET name = 'Nigiri Sushi' WHERE name='sushi';\nSELECT * FROM food;\n")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"1 row updated\n\n| name |\n|--------------|\n| Nigiri Sushi |\n| steak |\n")),(0,r.yg)("h4",{id:"deleting-data-and-querying"},"Deleting Data and Querying"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"DELETE name FROM food WHERE name = 'steak';\nSELECT * FROM food;\n")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"1 row deleted\n\n| name |\n|--------------|\n| Nigiri Sushi |\n")),(0,r.yg)("p",null,"Remember to replace placeholders with the appropriate values and paths when using the commands, and follow the structured steps for effective interaction with Parquet files using GlueSQL."),(0,r.yg)("p",null,"In rust."),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-rust"},'let path = "./";\nlet parquet_storage = ParquetStorage::new(path).unwrap();\nlet mut glue = Glue::new(parquet_storage);\nglue.execute("CREATE TABLE food (name TEXT);")\n .await\n .unwrap();\n\nglue.execute("INSERT INTO food VALUES(\'sushi\'), (\'steak\');")\n .await\n .unwrap();\n\nglue.execute("UPDATE food SET name = \'Nigiri Sushi\' WHERE name=\'sushi\';")\n .await\n .unwrap();\n\nglue.execute("DELETE name FROM food WHERE name = \'steak\';")\n .await\n .unwrap();\n\nglue.execute("SELECT * FROM food;").await.unwrap();\n')),(0,r.yg)("h2",{id:"schemaless-file-interaction"},"Schemaless File Interaction"),(0,r.yg)("p",null,"Parquet files inherently require a predefined schema. When creating tables without an explicit schema (schemaless tables), this extension establishes a temporary schema utilizing the Map datatype for the parquet file. This functionality ensures that even schemaless instances can process queries and modifications effectively."),(0,r.yg)("h3",{id:"implications"},"Implications"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},(0,r.yg)("strong",{parentName:"p"},"Ease of Interaction:")," The temporary schema creation allows users to interact with schemaless parquet files with ease, facilitating various operations such as data retrieval and modifications effectively.")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("p",{parentName:"li"},(0,r.yg)("strong",{parentName:"p"},"Structured Interaction:")," The use of the Map datatype as a temporary schema enables structured interaction with schemaless parquet files, ensuring a smooth user experience."))),(0,r.yg)("h3",{id:"examples-1"},"Examples"),(0,r.yg)("h4",{id:"creating-schemaless-table-inserting-and-querying-data"},"Creating Schemaless Table, Inserting, and Querying Data"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},'CREATE TABLE Logs;\nINSERT INTO Logs VALUES\n (\'{ "id": 1, "value": 30 }\'),\n (\'{ "id": 2, "rate": 3.0, "list": [1, 2, 3] }\'),\n (\'{ "id": 3, "rate": 5.0, "value": 100 }\');\nSELECT id, rate, list FROM Logs WHERE id = 2;\n')),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"Table created\n3 rows inserted\n\n| id | rate | list |\n|----|------|---------|\n| 2 | 3 | [1,2,3] |\n")),(0,r.yg)("h4",{id:"updating-data-and-querying-1"},"Updating Data and Querying"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"UPDATE Logs SET list='[5,6]' where id = 2;\nSELECT id, rate, list FROM Logs WHERE id = 2;\n")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"1 row updated\n| id | rate | list |\n|----|------|-------|\n| 2 | 3 | [5,6] |\n")),(0,r.yg)("h4",{id:"deleting-data-and-querying-1"},"Deleting Data and Querying"),(0,r.yg)("blockquote",null,(0,r.yg)("p",{parentName:"blockquote"},(0,r.yg)("strong",{parentName:"p"},"Caution: Deleting data in a schemaless table removes all the data within it"))),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-sql"},"DELETE from Logs where id = 2;\nSELECT id, rate, list FROM Logs WHERE id = 2;\n")),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-bash"},"1 row deleted\n| id | rate | list |\n")),(0,r.yg)("p",null,"In rust."),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-rust"},'let path = "./";\nlet parquet_storage = ParquetStorage::new(path).unwrap();\nlet mut glue = Glue::new(parquet_storage);\nglue.execute("CREATE TABLE Logs;")\n .await\n .unwrap();\n\nglue.execute("INSERT INTO Logs VALUES\n (\'{ "id": 1, "value": 30 }\'),\n (\'{ "id": 2, "rate": 3.0, "list": [1, 2, 3] }\'),\n (\'{ "id": 3, "rate": 5.0, "value": 100 }\');")\n .await\n .unwrap();\n\nglue.execute("UPDATE Logs SET list=\'[5,6]\' where id = 2;")\n .await\n .unwrap();\n\n//Caution: Deleting data in a schemaless table removes all the data within it\nglue.execute("DELETE from Logs where id = 2;")\n .await\n .unwrap();\n\nglue.execute("SELECT * FROM food;").await.unwrap();\n')),(0,r.yg)("h2",{id:"limitations"},"Limitations"),(0,r.yg)("ol",null,(0,r.yg)("li",{parentName:"ol"},(0,r.yg)("p",{parentName:"li"},"For Parquet files storing data with ",(0,r.yg)("inlineCode",{parentName:"p"},"parquet::record::api::Field::MapInternal"),", errors are encountered if the key information utilizes a data type other than string as the key.\nThis is attributed to the fact that GlueSQL's HashMap is of type <String, Value>, hence, limiting the use of other data types as keys.")),(0,r.yg)("li",{parentName:"ol"},(0,r.yg)("p",{parentName:"li"},"The interface for reading data in columnar units is currently not supported by GlueSQL, which might result in suboptimal read and write performance.")),(0,r.yg)("li",{parentName:"ol"},(0,r.yg)("p",{parentName:"li"},"Incompatibility with Parquet Physical Types:"))),(0,r.yg)("p",null,"GlueSQL currently lacks support for certain Parquet physical types, specifically INT96 and FIXED_LENGTH_BYTE_ARRAY. As a result, when executing data modification queries like INSERT or UPDATE on Parquet files, the data type for these columns will be transformed. Columns originally in the ",(0,r.yg)("inlineCode",{parentName:"p"},"INT96")," type will be changed to GlueSQL's ",(0,r.yg)("inlineCode",{parentName:"p"},"Int128"),", and those in ",(0,r.yg)("inlineCode",{parentName:"p"},"FIXED_LENGTH_BYTE_ARRAY")," will be converted to GlueSQL's ",(0,r.yg)("inlineCode",{parentName:"p"},"Bytea")," type. This conversion can have implications on data consistency and might necessitate additional transformations when interacting with other systems or tools that expect the original Parquet physical types."),(0,r.yg)("h2",{id:"conclusion"},"Conclusion"),(0,r.yg)("p",null,"Despite certain limitations, this extension significantly simplifies interactions with Parquet files, making GlueSQL a more versatile tool by supporting a popular columnar storage file format."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/f87e687e.8a0ae88d.js b/docs/0.16.0/assets/js/f87e687e.8a0ae88d.js new file mode 100644 index 00000000..b429734a --- /dev/null +++ b/docs/0.16.0/assets/js/f87e687e.8a0ae88d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[9251],{5680:(e,t,l)=>{l.d(t,{xA:()=>h,yg:()=>c});var a=l(6540);function r(e,t,l){return t in e?Object.defineProperty(e,t,{value:l,enumerable:!0,configurable:!0,writable:!0}):e[t]=l,e}function i(e,t){var l=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),l.push.apply(l,a)}return l}function g(e){for(var t=1;t<arguments.length;t++){var l=null!=arguments[t]?arguments[t]:{};t%2?i(Object(l),!0).forEach((function(t){r(e,t,l[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(l)):i(Object(l)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(l,t))}))}return e}function n(e,t){if(null==e)return{};var l,a,r=function(e,t){if(null==e)return{};var l,a,r={},i=Object.keys(e);for(a=0;a<i.length;a++)l=i[a],t.indexOf(l)>=0||(r[l]=e[l]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a<i.length;a++)l=i[a],t.indexOf(l)>=0||Object.prototype.propertyIsEnumerable.call(e,l)&&(r[l]=e[l])}return r}var u=a.createContext({}),p=function(e){var t=a.useContext(u),l=t;return e&&(l="function"==typeof e?e(t):g(g({},t),e)),l},h=function(e){var t=p(e.components);return a.createElement(u.Provider,{value:t},e.children)},s="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},o=a.forwardRef((function(e,t){var l=e.components,r=e.mdxType,i=e.originalType,u=e.parentName,h=n(e,["components","mdxType","originalType","parentName"]),s=p(l),o=r,c=s["".concat(u,".").concat(o)]||s[o]||m[o]||i;return l?a.createElement(c,g(g({ref:t},h),{},{components:l})):a.createElement(c,g({ref:t},h))}));function c(e,t){var l=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=l.length,g=new Array(i);g[0]=o;var n={};for(var u in t)hasOwnProperty.call(t,u)&&(n[u]=t[u]);n.originalType=e,n[s]="string"==typeof e?e:r,g[1]=n;for(var p=2;p<i;p++)g[p]=l[p];return a.createElement.apply(null,g)}return a.createElement.apply(null,l)}o.displayName="MDXCreateElement"},3112:(e,t,l)=>{l.r(t),l.d(t,{assets:()=>u,contentTitle:()=>g,default:()=>m,frontMatter:()=>i,metadata:()=>n,toc:()=>p});var a=l(8168),r=(l(6540),l(5680));const i={title:"Release v0.15",description:"Release Note - v0.15",slug:"release-v0.15",authors:[{name:"Taehoon Moon",title:"Creator of GlueSQL",url:"https://github.com/panarch",image_url:"https://github.com/panarch.png"}],tags:["v0.15","release-note"]},g=void 0,n={permalink:"/docs/0.16.0/blog/release-v0.15",source:"@site/blog/2023-11-18-release-v0.15.md",title:"Release v0.15",description:"Release Note - v0.15",date:"2023-11-18T00:00:00.000Z",formattedDate:"November 18, 2023",tags:[{label:"v0.15",permalink:"/docs/0.16.0/blog/tags/v-0-15"},{label:"release-note",permalink:"/docs/0.16.0/blog/tags/release-note"}],readingTime:5.93,hasTruncateMarker:!1,authors:[{name:"Taehoon Moon",title:"Creator of GlueSQL",url:"https://github.com/panarch",image_url:"https://github.com/panarch.png",imageURL:"https://github.com/panarch.png"}],frontMatter:{title:"Release v0.15",description:"Release Note - v0.15",slug:"release-v0.15",authors:[{name:"Taehoon Moon",title:"Creator of GlueSQL",url:"https://github.com/panarch",image_url:"https://github.com/panarch.png",imageURL:"https://github.com/panarch.png"}],tags:["v0.15","release-note"]},nextItem:{title:"GlueSQL - Revolutionizing Databases by Unifying Query Interfaces",permalink:"/docs/0.16.0/blog/revolutionizing-databases-by-unifying-query-interfaces"}},u={authorsImageUrls:[void 0]},p=[{value:"\ud83c\udf0a Breaking Changes",id:"-breaking-changes",level:2},{value:"\ud83c\udf40 Python Support",id:"-python-support",level:3},{value:"Code Samples",id:"code-samples",level:4},{value:"\ud83c\udf40 Redis Storage",id:"-redis-storage",level:3},{value:"\ud83c\udf40 CSV Storage",id:"-csv-storage",level:3},{value:"\ud83c\udf40 More operators and functions",id:"-more-operators-and-functions",level:3},{value:"\ud83d\ude80 Features",id:"-features",level:2},{value:"\ud83c\udf1f Improvements",id:"-improvements",level:2},{value:"\ud83d\udc1b Bug Fixes",id:"-bug-fixes",level:2},{value:"\ud83d\udc4f New Contributors",id:"-new-contributors",level:2}],h={toc:p},s="wrapper";function m(e){let{components:t,...l}=e;return(0,r.yg)(s,(0,a.A)({},h,l,{components:t,mdxType:"MDXLayout"}),(0,r.yg)("h2",{id:"-breaking-changes"},"\ud83c\udf0a Breaking Changes"),(0,r.yg)("h3",{id:"-python-support"},"\ud83c\udf40 Python Support"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"https://pypi.org/project/gluesql/"},"https://pypi.org/project/gluesql/"))),(0,r.yg)("h4",{id:"code-samples"},"Code Samples"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-python"},'from gluesql import Glue, MemoryStorage\nfrom tabulate import tabulate\n\ndb = Glue(MemoryStorage())\n\nsql = """\n SELECT\n u.name as user,\n d.name as device\n FROM User u\n JOIN Device d ON u.id = d.userId\n""".strip().replace(\n " ", ""\n)\n\nresult = db.query(sql)\nrows = result[0].get("rows")\nprint(f"\\n[Query]\\n{sql}")\nprint(tabulate(rows, headers="keys", showindex=True, tablefmt="simple_outline"))\n')),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"feat: Implement Python Binding ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/jopemachine"},"@jopemachine")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1357"},"#1357"),")")),(0,r.yg)("h3",{id:"-redis-storage"},"\ud83c\udf40 Redis Storage"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Feature: redis storage ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gurugio"},"@gurugio")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1396"},"#1396"),")")),(0,r.yg)("h3",{id:"-csv-storage"},"\ud83c\udf40 CSV Storage"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Add CsvStorage support to CLI \\& Rust package ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1437"},"#1437"),")"),(0,r.yg)("li",{parentName:"ul"},"Implement CSV Storage, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1280"},"#1280"),")")),(0,r.yg)("h3",{id:"-more-operators-and-functions"},"\ud83c\udf40 More operators and functions"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"feat: add index","_","by node ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/seonghun-dev"},"@seonghun-dev")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1355"},"#1355"),")"),(0,r.yg)("li",{parentName:"ul"},"Implement DEDUP function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/jinlee0"},"@jinlee0")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1430"},"#1430"),")"),(0,r.yg)("li",{parentName:"ul"},"Bitwise Shift Right Operator Implementation ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/2-NOW"},"@2-NOW")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1394"},"#1394"),")"),(0,r.yg)("li",{parentName:"ul"},"feat: implement ast","_","builder for values function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/tgsong827"},"@tgsong827")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1375"},"#1375"),")"),(0,r.yg)("li",{parentName:"ul"},"Implement ",(0,r.yg)("inlineCode",{parentName:"li"},"ADD_MONTH")," function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/kite707"},"@kite707")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1341"},"#1341"),")"),(0,r.yg)("li",{parentName:"ul"},"Implement ",(0,r.yg)("inlineCode",{parentName:"li"},"SPLICE")," function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/jinlee0"},"@jinlee0")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1371"},"#1371"),")"),(0,r.yg)("li",{parentName:"ul"},"Implement ",(0,r.yg)("inlineCode",{parentName:"li"},"SLICE")," function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/Kwontaehwon"},"@Kwontaehwon")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1340"},"#1340"),")"),(0,r.yg)("li",{parentName:"ul"},"Implement entries in ast builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/2-NOW"},"@2-NOW")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1364"},"#1364"),")"),(0,r.yg)("li",{parentName:"ul"},"Implement GREATEST function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/TheMan1697"},"@TheMan1697")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1312"},"#1312"),")"),(0,r.yg)("li",{parentName:"ul"},"Implement bitwise-not operator (~) in ast builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gurugio"},"@gurugio")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1366"},"#1366"),")"),(0,r.yg)("li",{parentName:"ul"},"Implement COALESCE function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/cake-monotone"},"@cake-monotone")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1333"},"#1333"),")"),(0,r.yg)("li",{parentName:"ul"},"feat: Implement select without table function in ast","_","builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ding-co"},"@ding-co")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1365"},"#1365"),")"),(0,r.yg)("li",{parentName:"ul"},"Add ExprWithAliasNode to ast builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/julia-ing"},"@julia-ing")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1359"},"#1359"),")"),(0,r.yg)("li",{parentName:"ul"},"feat: Implement take function in ast","_","builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ding-co"},"@ding-co")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1346"},"#1346"),")"),(0,r.yg)("li",{parentName:"ul"},"Implement last","_","day function in ast","_","builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/cjy13753"},"@cjy13753")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1344"},"#1344"),")"),(0,r.yg)("li",{parentName:"ul"},"Implement LAST","_","DAY function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1315"},"#1315")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/cjy13753"},"@cjy13753")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1323"},"#1323"),")"),(0,r.yg)("li",{parentName:"ul"},"Implement ast","_","builder for is","_","empty function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/julia-ing"},"@julia-ing")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1337"},"#1337"),")"),(0,r.yg)("li",{parentName:"ul"},"Implement ",(0,r.yg)("inlineCode",{parentName:"li"},"ast_builder")," for skip function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/cl-kim"},"@cl-kim")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1334"},"#1334"),")"),(0,r.yg)("li",{parentName:"ul"},"Implement ENTRIES function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/2-NOW"},"@2-NOW")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1315"},"#1315"),")"),(0,r.yg)("li",{parentName:"ul"},"Feature/operator bit not ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gurugio"},"@gurugio")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1321"},"#1321"),")"),(0,r.yg)("li",{parentName:"ul"},"Implement Skip function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/cl-kim"},"@cl-kim")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1325"},"#1325"),")"),(0,r.yg)("li",{parentName:"ul"},"Implement VALUES function for Map type ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/tgsong827"},"@tgsong827")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1288"},"#1288"),")"),(0,r.yg)("li",{parentName:"ul"},"Feat: impl bitwise-and operation ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/jinlee0"},"@jinlee0")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1281"},"#1281"),")"),(0,r.yg)("li",{parentName:"ul"},"Implement BIT","_","SHIFT","_","LEFT operation ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/codernineteen"},"@codernineteen")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1286"},"#1286"),")"),(0,r.yg)("li",{parentName:"ul"},"implement ",(0,r.yg)("inlineCode",{parentName:"li"},"SORT")," function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/Jaehui-Lee"},"@Jaehui-Lee")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1300"},"#1300"),")"),(0,r.yg)("li",{parentName:"ul"},"feat: Implement ",(0,r.yg)("inlineCode",{parentName:"li"},"LENGTH")," function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/jopemachine"},"@jopemachine")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1298"},"#1298"),")"),(0,r.yg)("li",{parentName:"ul"},"[Function]"," Implement TAKE function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ding-co"},"@ding-co")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1283"},"#1283"),")"),(0,r.yg)("li",{parentName:"ul"},"feat: implement ",(0,r.yg)("inlineCode",{parentName:"li"},"ast_builder")," for replace function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ChobobDev"},"@ChobobDev")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1275"},"#1275"),")"),(0,r.yg)("li",{parentName:"ul"},"feat: implement IS","_","EMPTY function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/julia-ing"},"@julia-ing")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1282"},"#1282"),")"),(0,r.yg)("li",{parentName:"ul"},"[Function]"," Implement REPLACE function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ChobobDev"},"@ChobobDev")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1266"},"#1266"),")"),(0,r.yg)("li",{parentName:"ul"},"Implement MD5 Function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/seonghun-dev"},"@seonghun-dev")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1242"},"#1242"),")"),(0,r.yg)("li",{parentName:"ul"},"[AST Builder]"," Implement ascii, chr function in ast ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/seonghun-dev"},"@seonghun-dev")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1244"},"#1244"),")"),(0,r.yg)("li",{parentName:"ul"},"[AST Builder]"," Implement Geometic Point Type and Geometric Function in AST Builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/seonghun-dev"},"@seonghun-dev")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1222"},"#1222"),")")),(0,r.yg)("h2",{id:"-features"},"\ud83d\ude80 Features"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"feat: implement ",(0,r.yg)("inlineCode",{parentName:"li"},"select")," iterator utility function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1429"},"#1429"),")")),(0,r.yg)("h2",{id:"-improvements"},"\ud83c\udf1f Improvements"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"Fix parsing of BigDecimal literals with zero fraction part as floats, not integer ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/zmrdltl"},"@zmrdltl")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1416"},"#1416"),")"),(0,r.yg)("li",{parentName:"ul"},"Update docs/ast-builder padding.md code block lang keyword, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1436"},"#1436"),")"),(0,r.yg)("li",{parentName:"ul"},"Support StoreMut trait to Optional ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/seonghun-dev"},"@seonghun-dev")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1435"},"#1435"),")"),(0,r.yg)("li",{parentName:"ul"},"docs: write docmentation for padding ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1434"},"#1434"),")"),(0,r.yg)("li",{parentName:"ul"},"test: add test cases for astb-padding ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1433"},"#1433"),")"),(0,r.yg)("li",{parentName:"ul"},"Upgrade to chrono v0.4.31 and adjust millisecond value in Timestamp Creation ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/zmrdltl"},"@zmrdltl")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1427"},"#1427"),")"),(0,r.yg)("li",{parentName:"ul"},"Remove unnecessary comments in evalaute/function.rs ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1431"},"#1431"),")"),(0,r.yg)("li",{parentName:"ul"},"write docmentation for character","_","conversion ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1428"},"#1428"),")"),(0,r.yg)("li",{parentName:"ul"},"docs: Add ",(0,r.yg)("inlineCode",{parentName:"li"},"SLICE")," function doc ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/fregataa"},"@fregataa")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1425"},"#1425"),")"),(0,r.yg)("li",{parentName:"ul"},"test: add cases to character","_","conversion ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1424"},"#1424"),")"),(0,r.yg)("li",{parentName:"ul"},"docs:Add doc about SPLICE function ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/jinlee0"},"@jinlee0")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1423"},"#1423"),")"),(0,r.yg)("li",{parentName:"ul"},"Change store RowIter type from Iterator to Stream ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1419"},"#1419"),")"),(0,r.yg)("li",{parentName:"ul"},"Reflect Deprecation of ",(0,r.yg)("inlineCode",{parentName:"li"},"from_utc")," in Crate ",(0,r.yg)("inlineCode",{parentName:"li"},"chrono")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/zmrdltl"},"@zmrdltl")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1415"},"#1415"),")"),(0,r.yg)("li",{parentName:"ul"},"Remove eval","_","to","_","{int|float..} macro uses in core/../evaluate/function.rs, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1361"},"#1361"),")"),(0,r.yg)("li",{parentName:"ul"},"test: write example for ast builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/daengdaengLee"},"@daengdaengLee")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1259"},"#1259"),")"),(0,r.yg)("li",{parentName:"ul"},"Fix merge conflict in data/value/mod.rs ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1406"},"#1406"),")"),(0,r.yg)("li",{parentName:"ul"},"chore: implement ",(0,r.yg)("inlineCode",{parentName:"li"},"ConvertError"),", ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1401"},"#1401"),")"),(0,r.yg)("li",{parentName:"ul"},"refactor: remove implementation of from Value trait for Evaluated ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/tgsong827"},"@tgsong827")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1399"},"#1399"),")"),(0,r.yg)("li",{parentName:"ul"},"refactor: update function module's namespacing in ast","_","builder ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/tgsong827"},"@tgsong827")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1398"},"#1398"),")"),(0,r.yg)("li",{parentName:"ul"},"chore: remove ",(0,r.yg)("inlineCode",{parentName:"li"},"Result")," from ",(0,r.yg)("inlineCode",{parentName:"li"},"ast_builder::transaction")," return type ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1404"},"#1404"),")"),(0,r.yg)("li",{parentName:"ul"},"chore: bump rust version to 1.72 ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1388"},"#1388"),")"),(0,r.yg)("li",{parentName:"ul"},"chore: add example of convert from payload to custom struct ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1379"},"#1379"),")"),(0,r.yg)("li",{parentName:"ul"},"Update Chrono version to 0.4.26, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1374"},"#1374"),")"),(0,r.yg)("li",{parentName:"ul"},"Update test-suite Tester::run to return Payload, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1373"},"#1373"),")"),(0,r.yg)("li",{parentName:"ul"},"Remove .unwrap() uses in test-suite/ test codes, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1372"},"#1372"),")"),(0,r.yg)("li",{parentName:"ul"},"Replace run!, test! and count! macros in test-suite to Tester methods, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1368"},"#1368"),")"),(0,r.yg)("li",{parentName:"ul"},"Update coverage.yml gh-action to ignore await only lines, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1370"},"#1370"),")"),(0,r.yg)("li",{parentName:"ul"},"Apply pretty","_","assertions::assert","_","eq! to core/ ast","_","builder unit tests ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1369"},"#1369"),")"),(0,r.yg)("li",{parentName:"ul"},"Simplify value evaluate cmp with literal ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1353"},"#1353"),")"),(0,r.yg)("li",{parentName:"ul"},"Update gh-action author assign - add zmrdltl to reviewers ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1342"},"#1342"),")"),(0,r.yg)("li",{parentName:"ul"},"Refactor GCD and LCM functions ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/cake-monotone"},"@cake-monotone")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1331"},"#1331"),")"),(0,r.yg)("li",{parentName:"ul"},"Refactor write","_","rows ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1319"},"#1319"),")"),(0,r.yg)("li",{parentName:"ul"},"Js pkg wasm pack build not to generate readme and packagejson ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1327"},"#1327"),")"),(0,r.yg)("li",{parentName:"ul"},"Update pkg/javascript dist directories to use dist","_","web/ and dist","_","node\u2026 ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1326"},"#1326"),")"),(0,r.yg)("li",{parentName:"ul"},"Upgrade bigdecimal to 0.4.1, sqlparser to 0.36.1 ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/jinlee0"},"@jinlee0")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1322"},"#1322"),")"),(0,r.yg)("li",{parentName:"ul"},"Update wasm-pack-action version to 0.4.0, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1316"},"#1316"),")"),(0,r.yg)("li",{parentName:"ul"},"Update JavaScript package load","_","indexeddb method to get namespace as a\u2026 ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1320"},"#1320"),")"),(0,r.yg)("li",{parentName:"ul"},"Upgrade sqlparser-rs version to 0.35, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1292"},"#1292"),")"),(0,r.yg)("li",{parentName:"ul"},"Remove unused error variant in JsonStorage ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1278"},"#1278"),")"),(0,r.yg)("li",{parentName:"ul"},"Implement CAST text literal or value to MAP or LIST, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1267"},"#1267"),")"),(0,r.yg)("li",{parentName:"ul"},"Simplity JsonStorage Store::fetch","_","all","_","schemas codes, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1264"},"#1264"),")"),(0,r.yg)("li",{parentName:"ul"},"Change console.log in gluesql.js -> console.debug ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/parkma99"},"@parkma99")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1256"},"#1256"),")"),(0,r.yg)("li",{parentName:"ul"},"Replace ",(0,r.yg)("inlineCode",{parentName:"li"},"actions-rs/toolchain")," with ",(0,r.yg)("inlineCode",{parentName:"li"},"dtolnay/rust-toolchain")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/jongwooo"},"@jongwooo")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1251"},"#1251"),")"),(0,r.yg)("li",{parentName:"ul"},"ci: Automatically assign a PR to its author ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/rapsealk"},"@rapsealk")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1253"},"#1253"),")"),(0,r.yg)("li",{parentName:"ul"},"Remove sync methods in core/ Glue struct, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1247"},"#1247"),")"),(0,r.yg)("li",{parentName:"ul"},"Remove test function in test-suite tester, ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1246"},"#1246"),")"),(0,r.yg)("li",{parentName:"ul"},"fix: allow interval cast-related functions to accept only literals instead of evaluations ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ever0de"},"@ever0de")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1238"},"#1238"),")"),(0,r.yg)("li",{parentName:"ul"},"Split custom Partial{Eq|Ord} impl of Value \\& Literal into evaluate","_","{eq|cmp} ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1233"},"#1233"),")"),(0,r.yg)("li",{parentName:"ul"},"Improve example codes formatting ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/jopemachine"},"@jopemachine")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1235"},"#1235"),")"),(0,r.yg)("li",{parentName:"ul"},"feat: fmt list and map ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/Mehrbod2002"},"@Mehrbod2002")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1226"},"#1226"),")"),(0,r.yg)("li",{parentName:"ul"},"Update README.md - add blog article links ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1232"},"#1232"),")"),(0,r.yg)("li",{parentName:"ul"},"Write the blog article - revolutionizing databases by unifying the qu\u2026 ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1231"},"#1231"),")"),(0,r.yg)("li",{parentName:"ul"},"Write the blog article - test driven documentation ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1229"},"#1229"),")"),(0,r.yg)("li",{parentName:"ul"},"Write the blog article - breaking the boundary between sql and nosql \u2026 ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1228"},"#1228"),")"),(0,r.yg)("li",{parentName:"ul"},"Add test and doc for ast-builder::statements::querying::data-aggregation ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1224"},"#1224"),")")),(0,r.yg)("h2",{id:"-bug-fixes"},"\ud83d\udc1b Bug Fixes"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},"fix: Literal comparison with BinaryOperator ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ding-co"},"@ding-co")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1397"},"#1397"),")"),(0,r.yg)("li",{parentName:"ul"},"fix: update Key.cmp to compare a type with other type ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/tgsong827"},"@tgsong827")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1367"},"#1367"),")"),(0,r.yg)("li",{parentName:"ul"},"Fix Value::evaluate","_","cmp","_","with","_","literal between Decimal and Literal::Num\u2026 ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1352"},"#1352"),")"),(0,r.yg)("li",{parentName:"ul"},"Fix spool on ",(0,r.yg)("inlineCode",{parentName:"li"},"tabular off")," and ",(0,r.yg)("inlineCode",{parentName:"li"},"SelectMap")," ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/devgony"},"@devgony")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1314"},"#1314"),")"),(0,r.yg)("li",{parentName:"ul"},"Update auto-assign-action to be triggered on PR open from fork repos ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1313"},"#1313"),")"),(0,r.yg)("li",{parentName:"ul"},"Fix Scala Subquery should contain only 1 column ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/ChobobDev"},"@ChobobDev")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1284"},"#1284"),")"),(0,r.yg)("li",{parentName:"ul"},"Wrap config path by quotes in auto-author-assign.yml ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1258"},"#1258"),")"),(0,r.yg)("li",{parentName:"ul"},"Apply word-wrap to docs/ article h1 ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1230"},"#1230"),")"),(0,r.yg)("li",{parentName:"ul"},"Fix docusaurus.config.js themeConfig handler ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/panarch"},"@panarch")," (",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1225"},"#1225"),")")),(0,r.yg)("h2",{id:"-new-contributors"},"\ud83d\udc4f New Contributors"),(0,r.yg)("ul",null,(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"https://github.com/Mehrbod2002"},"@Mehrbod2002")," made their first contribution in ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1226"},"https://github.com/gluesql/gluesql/pull/1226")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"https://github.com/jopemachine"},"@jopemachine")," made their first contribution in ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1235"},"https://github.com/gluesql/gluesql/pull/1235")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"https://github.com/rapsealk"},"@rapsealk")," made their first contribution in ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1253"},"https://github.com/gluesql/gluesql/pull/1253")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"https://github.com/parkma99"},"@parkma99")," made their first contribution in ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1256"},"https://github.com/gluesql/gluesql/pull/1256")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"https://github.com/julia-ing"},"@julia-ing")," made their first contribution in ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1282"},"https://github.com/gluesql/gluesql/pull/1282")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"https://github.com/ding-co"},"@ding-co")," made their first contribution in ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1283"},"https://github.com/gluesql/gluesql/pull/1283")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"https://github.com/Jaehui-Lee"},"@Jaehui-Lee")," made their first contribution in ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1300"},"https://github.com/gluesql/gluesql/pull/1300")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"https://github.com/jinlee0"},"@jinlee0")," made their first contribution in ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1322"},"https://github.com/gluesql/gluesql/pull/1322")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"https://github.com/codernineteen"},"@codernineteen")," made their first contribution in ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1286"},"https://github.com/gluesql/gluesql/pull/1286")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"https://github.com/tgsong827"},"@tgsong827")," made their first contribution in ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1288"},"https://github.com/gluesql/gluesql/pull/1288")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"https://github.com/cl-kim"},"@cl-kim")," made their first contribution in ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1325"},"https://github.com/gluesql/gluesql/pull/1325")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"https://github.com/gurugio"},"@gurugio")," made their first contribution in ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1321"},"https://github.com/gluesql/gluesql/pull/1321")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"https://github.com/2-NOW"},"@2-NOW")," made their first contribution in ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1315"},"https://github.com/gluesql/gluesql/pull/1315")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"https://github.com/cake-monotone"},"@cake-monotone")," made their first contribution in ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1331"},"https://github.com/gluesql/gluesql/pull/1331")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"https://github.com/cjy13753"},"@cjy13753")," made their first contribution in ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1323"},"https://github.com/gluesql/gluesql/pull/1323")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"https://github.com/TheMan1697"},"@TheMan1697")," made their first contribution in ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1312"},"https://github.com/gluesql/gluesql/pull/1312")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"https://github.com/Kwontaehwon"},"@Kwontaehwon")," made their first contribution in ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1340"},"https://github.com/gluesql/gluesql/pull/1340")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"https://github.com/kite707"},"@kite707")," made their first contribution in ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1341"},"https://github.com/gluesql/gluesql/pull/1341")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"https://github.com/daengdaengLee"},"@daengdaengLee")," made their first contribution in ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1259"},"https://github.com/gluesql/gluesql/pull/1259")),(0,r.yg)("li",{parentName:"ul"},(0,r.yg)("a",{parentName:"li",href:"https://github.com/fregataa"},"@fregataa")," made their first contribution in ",(0,r.yg)("a",{parentName:"li",href:"https://github.com/gluesql/gluesql/pull/1425"},"https://github.com/gluesql/gluesql/pull/1425"))),(0,r.yg)("p",null,(0,r.yg)("strong",{parentName:"p"},"Full Changelog"),": ",(0,r.yg)("a",{parentName:"p",href:"https://github.com/gluesql/gluesql/compare/v0.14.0...v0.15.0"},"https://github.com/gluesql/gluesql/compare/v0.14.0...v0.15.0")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/f914cfe8.0c3fe5c5.js b/docs/0.16.0/assets/js/f914cfe8.0c3fe5c5.js new file mode 100644 index 00000000..e6721269 --- /dev/null +++ b/docs/0.16.0/assets/js/f914cfe8.0c3fe5c5.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[1403],{5680:(e,t,n)=>{n.d(t,{xA:()=>u,yg:()=>f});var r=n(6540);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?a(Object(n),!0).forEach((function(t){o(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):a(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function c(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},a=Object.keys(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=r.createContext({}),l=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},u=function(e){var t=l(e.components);return r.createElement(s.Provider,{value:t},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},y=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,s=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),d=l(n),y=o,f=d["".concat(s,".").concat(y)]||d[y]||p[y]||a;return n?r.createElement(f,i(i({ref:t},u),{},{components:n})):r.createElement(f,i({ref:t},u))}));function f(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,i=new Array(a);i[0]=y;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c[d]="string"==typeof e?e:o,i[1]=c;for(var l=2;l<a;l++)i[l]=n[l];return r.createElement.apply(null,i)}return r.createElement.apply(null,n)}y.displayName="MDXCreateElement"},3124:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>p,frontMatter:()=>a,metadata:()=>c,toc:()=>l});var r=n(8168),o=(n(6540),n(5680));const a={},i="Data Selection and Projection",c={unversionedId:"ast-builder/statements/querying/data-selection-and-projection",id:"ast-builder/statements/querying/data-selection-and-projection",title:"Data Selection and Projection",description:"Todo",source:"@site/docs/ast-builder/statements/querying/data-selection-and-projection.md",sourceDirName:"ast-builder/statements/querying",slug:"/ast-builder/statements/querying/data-selection-and-projection",permalink:"/docs/0.16.0/ast-builder/statements/querying/data-selection-and-projection",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"Data Joining",permalink:"/docs/0.16.0/ast-builder/statements/querying/data-joining"},next:{title:"Data Sorting and Limiting",permalink:"/docs/0.16.0/ast-builder/statements/querying/data-sorting-and-limiting"}},s={},l=[{value:"Todo",id:"todo",level:2}],u={toc:l},d="wrapper";function p(e){let{components:t,...n}=e;return(0,o.yg)(d,(0,r.A)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,o.yg)("h1",{id:"data-selection-and-projection"},"Data Selection and Projection"),(0,o.yg)("h2",{id:"todo"},"Todo"),(0,o.yg)("pre",null,(0,o.yg)("code",{parentName:"pre"},"- FILTER: Filters rows in a dataset based on specified conditions.\n- PROJECT: Selects which columns to include in the result set.\n")))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/f9553497.6168470e.js b/docs/0.16.0/assets/js/f9553497.6168470e.js new file mode 100644 index 00000000..258e2a86 --- /dev/null +++ b/docs/0.16.0/assets/js/f9553497.6168470e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[2495],{5680:(e,t,n)=>{n.d(t,{xA:()=>u,yg:()=>f});var i=n(6540);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,i)}return n}function a(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,i,r=function(e,t){if(null==e)return{};var n,i,r={},o=Object.keys(e);for(i=0;i<o.length;i++)n=o[i],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(i=0;i<o.length;i++)n=o[i],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=i.createContext({}),d=function(e){var t=i.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},u=function(e){var t=d(e.components);return i.createElement(l.Provider,{value:t},e.children)},p="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},g=i.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=d(n),g=r,f=p["".concat(l,".").concat(g)]||p[g]||c[g]||o;return n?i.createElement(f,a(a({ref:t},u),{},{components:n})):i.createElement(f,a({ref:t},u))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,a=new Array(o);a[0]=g;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[p]="string"==typeof e?e:r,a[1]=s;for(var d=2;d<o;d++)a[d]=n[d];return i.createElement.apply(null,a)}return i.createElement.apply(null,n)}g.displayName="MDXCreateElement"},3947:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>a,default:()=>c,frontMatter:()=>o,metadata:()=>s,toc:()=>d});var i=n(8168),r=(n(6540),n(5680));const o={},a="Position and Indexing",s={unversionedId:"ast-builder/functions/text/position-and-indexing",id:"ast-builder/functions/text/position-and-indexing",title:"Position and Indexing",description:"GlueSQL provides several functions for text manipulation, including finding the index of a substring (find_idx), finding the position of a substring (position), and getting the leftmost or rightmost characters (left and right).",source:"@site/docs/ast-builder/functions/text/position-and-indexing.md",sourceDirName:"ast-builder/functions/text",slug:"/ast-builder/functions/text/position-and-indexing",permalink:"/docs/0.16.0/ast-builder/functions/text/position-and-indexing",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"Padding",permalink:"/docs/0.16.0/ast-builder/functions/text/padding"},next:{title:"Text Manipulation",permalink:"/docs/0.16.0/ast-builder/functions/text/text-manipulation"}},l={},d=[{value:"Find Index - find_idx",id:"find-index---find_idx",level:2},{value:"Position - position",id:"position---position",level:2},{value:"Left - left",id:"left---left",level:2},{value:"Right - right",id:"right---right",level:2}],u={toc:d},p="wrapper";function c(e){let{components:t,...n}=e;return(0,r.yg)(p,(0,i.A)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,r.yg)("h1",{id:"position-and-indexing"},"Position and Indexing"),(0,r.yg)("p",null,"GlueSQL provides several functions for text manipulation, including finding the index of a substring (",(0,r.yg)("inlineCode",{parentName:"p"},"find_idx"),"), finding the position of a substring (",(0,r.yg)("inlineCode",{parentName:"p"},"position"),"), and getting the leftmost or rightmost characters (",(0,r.yg)("inlineCode",{parentName:"p"},"left")," and ",(0,r.yg)("inlineCode",{parentName:"p"},"right"),")."),(0,r.yg)("h2",{id:"find-index---find_idx"},"Find Index - find_idx"),(0,r.yg)("p",null,(0,r.yg)("inlineCode",{parentName:"p"},"find_idx")," function returns the first position of the specified substring, starting from the beginning of the string or the specified position."),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-rust"},'let test_num = find_idx(text("strawberry"), text("berry"), None); // Returns 6\nlet test_num = find_idx(text("Oracle Database 12c Release"), text("as"), Some(num(15))); // Returns 25\n')),(0,r.yg)("p",null,"You can also call ",(0,r.yg)("inlineCode",{parentName:"p"},"find_idx")," directly on a string:"),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-rust"},'let test_num = text("Oracle Database 12c Release").find_idx(text("as"), Some(num(15))); // Returns 25\n')),(0,r.yg)("h2",{id:"position---position"},"Position - position"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"position")," function is similar to ",(0,r.yg)("inlineCode",{parentName:"p"},"find_idx"),", but it starts counting from 1 and does not take a third argument for the starting position."),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-rust"},'let test_num = position(text("cake"), text("ke")); // Returns 3\n')),(0,r.yg)("h2",{id:"left---left"},"Left - left"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"left")," function returns the leftmost characters of a string. The second argument specifies the number of characters to return."),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-rust"},'let test_str = left(text("Hello, World"), num(7)); // Returns "Hello, "\n')),(0,r.yg)("h2",{id:"right---right"},"Right - right"),(0,r.yg)("p",null,"The ",(0,r.yg)("inlineCode",{parentName:"p"},"right")," function returns the rightmost characters of a string. The second argument specifies the number of characters to return."),(0,r.yg)("pre",null,(0,r.yg)("code",{parentName:"pre",className:"language-rust"},'let test_str = right(text("Hello, World"), num(7)); // Returns ", World"\n')))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/fa5466f2.c7b13c43.js b/docs/0.16.0/assets/js/fa5466f2.c7b13c43.js new file mode 100644 index 00000000..c2664130 --- /dev/null +++ b/docs/0.16.0/assets/js/fa5466f2.c7b13c43.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[3679],{5680:(e,n,t)=>{t.d(n,{xA:()=>p,yg:()=>y});var r=t(6540);function l(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function a(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function i(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?a(Object(t),!0).forEach((function(n){l(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):a(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function s(e,n){if(null==e)return{};var t,r,l=function(e,n){if(null==e)return{};var t,r,l={},a=Object.keys(e);for(r=0;r<a.length;r++)t=a[r],n.indexOf(t)>=0||(l[t]=e[t]);return l}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)t=a[r],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(l[t]=e[t])}return l}var o=r.createContext({}),u=function(e){var n=r.useContext(o),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},p=function(e){var n=u(e.components);return r.createElement(o.Provider,{value:n},e.children)},m="mdxType",c={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},g=r.forwardRef((function(e,n){var t=e.components,l=e.mdxType,a=e.originalType,o=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),m=u(t),g=l,y=m["".concat(o,".").concat(g)]||m[g]||c[g]||a;return t?r.createElement(y,i(i({ref:n},p),{},{components:t})):r.createElement(y,i({ref:n},p))}));function y(e,n){var t=arguments,l=n&&n.mdxType;if("string"==typeof e||l){var a=t.length,i=new Array(a);i[0]=g;var s={};for(var o in n)hasOwnProperty.call(n,o)&&(s[o]=n[o]);s.originalType=e,s[m]="string"==typeof e?e:l,i[1]=s;for(var u=2;u<a;u++)i[u]=t[u];return r.createElement.apply(null,i)}return r.createElement.apply(null,t)}g.displayName="MDXCreateElement"},7587:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>o,contentTitle:()=>i,default:()=>c,frontMatter:()=>a,metadata:()=>s,toc:()=>u});var r=t(8168),l=(t(6540),t(5680));const a={},i="IFNULL",s={unversionedId:"sql-syntax/functions/others/ifnull",id:"sql-syntax/functions/others/ifnull",title:"IFNULL",description:"The IFNULL function is used to return the first non-null value among the provided expressions. It takes two arguments and checks if the first argument is NULL. If the first argument is NULL, it returns the second argument; otherwise, it returns the first argument.",source:"@site/docs/sql-syntax/functions/others/ifnull.md",sourceDirName:"sql-syntax/functions/others",slug:"/sql-syntax/functions/others/ifnull",permalink:"/docs/0.16.0/sql-syntax/functions/others/ifnull",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"GENERATE_UUID",permalink:"/docs/0.16.0/sql-syntax/functions/others/generate-uuid"},next:{title:"Introduction",permalink:"/docs/0.16.0/ast-builder/intro"}},o={},u=[{value:"Syntax",id:"syntax",level:2},{value:"Examples",id:"examples",level:2}],p={toc:u},m="wrapper";function c(e){let{components:n,...t}=e;return(0,l.yg)(m,(0,r.A)({},p,t,{components:n,mdxType:"MDXLayout"}),(0,l.yg)("h1",{id:"ifnull"},"IFNULL"),(0,l.yg)("p",null,"The ",(0,l.yg)("inlineCode",{parentName:"p"},"IFNULL")," function is used to return the first non-null value among the provided expressions. It takes two arguments and checks if the first argument is NULL. If the first argument is NULL, it returns the second argument; otherwise, it returns the first argument."),(0,l.yg)("h2",{id:"syntax"},"Syntax"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"IFNULL(expression1, expression2)\n")),(0,l.yg)("h2",{id:"examples"},"Examples"),(0,l.yg)("p",null,"Consider the following ",(0,l.yg)("inlineCode",{parentName:"p"},"SingleItem")," table:"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE SingleItem (\n id INTEGER NULL,\n int8 INT8 NULL,\n dec DECIMAL NULL,\n dt DATE NULL,\n mystring TEXT NULL,\n mybool BOOLEAN NULL,\n myfloat FLOAT NULL,\n mytime TIME NULL,\n mytimestamp TIMESTAMP NULL\n);\n")),(0,l.yg)("p",null,"Insert two records into the ",(0,l.yg)("inlineCode",{parentName:"p"},"SingleItem")," table:"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO SingleItem VALUES (0, 1, 2, '2022-05-23', 'this is a string', true, 3.15, '01:02:03', '1970-01-01 00:00:00 -00:00');\nINSERT INTO SingleItem VALUES (null, null, null, null, null, null, null, null, null);\n")),(0,l.yg)("p",null,"Example 1: Using ",(0,l.yg)("inlineCode",{parentName:"p"},"IFNULL")," with integer values:"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT IFNULL(id, 1) AS myid, IFNULL(int8, 2) AS int8, IFNULL(dec, 3)\nFROM SingleItem WHERE id IS NOT NULL;\n")),(0,l.yg)("p",null,"Example 2: Using ",(0,l.yg)("inlineCode",{parentName:"p"},"IFNULL")," with date and text values:"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT IFNULL(dt, '2000-01-01') AS mydate, IFNULL(mystring, 'blah') AS name\nFROM SingleItem WHERE id IS NOT NULL;\n")),(0,l.yg)("p",null,"Example 3: Using ",(0,l.yg)("inlineCode",{parentName:"p"},"IFNULL")," with boolean and float values:"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT IFNULL(mybool, 'YES') AS mybool, IFNULL(myfloat, 'NO') AS myfloat\nFROM SingleItem WHERE id IS NOT NULL;\n")),(0,l.yg)("p",null,"Example 4: Using ",(0,l.yg)("inlineCode",{parentName:"p"},"IFNULL")," with time and timestamp values:"),(0,l.yg)("pre",null,(0,l.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT IFNULL(mytime, 'YES') AS mybool, IFNULL(mytimestamp, 'NO') AS myfloat\nFROM SingleItem WHERE id IS NOT NULL;\n")))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/faca410e.0cb58136.js b/docs/0.16.0/assets/js/faca410e.0cb58136.js new file mode 100644 index 00000000..65c883a9 --- /dev/null +++ b/docs/0.16.0/assets/js/faca410e.0cb58136.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[2160],{5680:(e,n,t)=>{t.d(n,{xA:()=>p,yg:()=>y});var r=t(6540);function a(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function o(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function l(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?o(Object(t),!0).forEach((function(n){a(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):o(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function i(e,n){if(null==e)return{};var t,r,a=function(e,n){if(null==e)return{};var t,r,a={},o=Object.keys(e);for(r=0;r<o.length;r++)t=o[r],n.indexOf(t)>=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r<o.length;r++)t=o[r],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var s=r.createContext({}),u=function(e){var n=r.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):l(l({},n),e)),t},p=function(e){var n=u(e.components);return r.createElement(s.Provider,{value:n},e.children)},c="mdxType",f={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},m=r.forwardRef((function(e,n){var t=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),c=u(t),m=a,y=c["".concat(s,".").concat(m)]||c[m]||f[m]||o;return t?r.createElement(y,l(l({ref:n},p),{},{components:t})):r.createElement(y,l({ref:n},p))}));function y(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var o=t.length,l=new Array(o);l[0]=m;var i={};for(var s in n)hasOwnProperty.call(n,s)&&(i[s]=n[s]);i.originalType=e,i[c]="string"==typeof e?e:a,l[1]=i;for(var u=2;u<o;u++)l[u]=t[u];return r.createElement.apply(null,l)}return r.createElement.apply(null,t)}m.displayName="MDXCreateElement"},4271:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>s,contentTitle:()=>l,default:()=>f,frontMatter:()=>o,metadata:()=>i,toc:()=>u});var r=t(8168),a=(t(6540),t(5680));const o={},l="EXP",i={unversionedId:"sql-syntax/functions/math/exp",id:"sql-syntax/functions/math/exp",title:"EXP",description:"The EXP function is used to calculate the exponential value of a number. It takes a single FLOAT or INTEGER argument and returns a FLOAT value representing the exponential value of the given number.",source:"@site/docs/sql-syntax/functions/math/exp.md",sourceDirName:"sql-syntax/functions/math",slug:"/sql-syntax/functions/math/exp",permalink:"/docs/0.16.0/sql-syntax/functions/math/exp",draft:!1,tags:[],version:"current",frontMatter:{},sidebar:"autoSidebar",previous:{title:"DIV",permalink:"/docs/0.16.0/sql-syntax/functions/math/div"},next:{title:"FLOOR",permalink:"/docs/0.16.0/sql-syntax/functions/math/floor"}},s={},u=[{value:"Example",id:"example",level:2},{value:"Errors",id:"errors",level:2}],p={toc:u},c="wrapper";function f(e){let{components:n,...t}=e;return(0,a.yg)(c,(0,r.A)({},p,t,{components:n,mdxType:"MDXLayout"}),(0,a.yg)("h1",{id:"exp"},"EXP"),(0,a.yg)("p",null,"The ",(0,a.yg)("inlineCode",{parentName:"p"},"EXP")," function is used to calculate the exponential value of a number. It takes a single FLOAT or INTEGER argument and returns a FLOAT value representing the exponential value of the given number."),(0,a.yg)("h2",{id:"example"},"Example"),(0,a.yg)("p",null,"The following example demonstrates the usage of the ",(0,a.yg)("inlineCode",{parentName:"p"},"EXP")," function in a SQL query:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT\n EXP(2.0) as exp1,\n EXP(5.5) as exp2;\n")),(0,a.yg)("p",null,"This will return the following result:"),(0,a.yg)("pre",null,(0,a.yg)("code",{parentName:"pre"},"exp1 | exp2\n---------------+-------------------\n2.0_f64.exp() | 5.5_f64.exp()\n")),(0,a.yg)("h2",{id:"errors"},"Errors"),(0,a.yg)("ol",null,(0,a.yg)("li",{parentName:"ol"},"If the argument is not of FLOAT or INTEGER type, a ",(0,a.yg)("inlineCode",{parentName:"li"},"FunctionRequiresFloatValue")," error will be raised."),(0,a.yg)("li",{parentName:"ol"},"If the number of arguments provided to the function is not equal to 1, a ",(0,a.yg)("inlineCode",{parentName:"li"},"FunctionArgsLengthNotMatching")," error will be raised.")))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/ff7b8d8e.2839820c.js b/docs/0.16.0/assets/js/ff7b8d8e.2839820c.js new file mode 100644 index 00000000..cb309d36 --- /dev/null +++ b/docs/0.16.0/assets/js/ff7b8d8e.2839820c.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[85],{5680:(e,t,n)=>{n.d(t,{xA:()=>p,yg:()=>g});var a=n(6540);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?r(Object(n),!0).forEach((function(t){i(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):r(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,a,i=function(e,t){if(null==e)return{};var n,a,i={},r=Object.keys(e);for(a=0;a<r.length;a++)n=r[a],t.indexOf(n)>=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a<r.length;a++)n=r[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=a.createContext({}),m=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=m(e.components);return a.createElement(s.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},c=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,r=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),u=m(n),c=i,g=u["".concat(s,".").concat(c)]||u[c]||d[c]||r;return n?a.createElement(g,o(o({ref:t},p),{},{components:n})):a.createElement(g,o({ref:t},p))}));function g(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=n.length,o=new Array(r);o[0]=c;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[u]="string"==typeof e?e:i,o[1]=l;for(var m=2;m<r;m++)o[m]=n[m];return a.createElement.apply(null,o)}return a.createElement.apply(null,n)}c.displayName="MDXCreateElement"},1088:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>d,frontMatter:()=>r,metadata:()=>l,toc:()=>m});var a=n(8168),i=(n(6540),n(5680));const r={sidebar_position:8},o="TIME",l={unversionedId:"sql-syntax/data-types/time",id:"sql-syntax/data-types/time",title:"TIME",description:"In GlueSQL, the TIME data type is used to store time values in the format 'HHSS.SSS'. The code snippet provided demonstrates how to create a table with TIME columns, insert data into it, and perform various queries and operations on the data.",source:"@site/docs/sql-syntax/data-types/time.md",sourceDirName:"sql-syntax/data-types",slug:"/sql-syntax/data-types/time",permalink:"/docs/0.16.0/sql-syntax/data-types/time",draft:!1,tags:[],version:"current",sidebarPosition:8,frontMatter:{sidebar_position:8},sidebar:"autoSidebar",previous:{title:"TIMESTAMP",permalink:"/docs/0.16.0/sql-syntax/data-types/timestamp"},next:{title:"INTERVAL",permalink:"/docs/0.16.0/sql-syntax/data-types/interval"}},s={},m=[{value:"Creating a table with TIME columns",id:"creating-a-table-with-time-columns",level:2},{value:"Inserting data into a table with TIME columns",id:"inserting-data-into-a-table-with-time-columns",level:2},{value:"Querying data from a table with TIME columns",id:"querying-data-from-a-table-with-time-columns",level:2},{value:"Filtering data using TIME columns",id:"filtering-data-using-time-columns",level:2},{value:"Performing time arithmetic",id:"performing-time-arithmetic",level:2},{value:"Handling invalid time values",id:"handling-invalid-time-values",level:2},{value:"Conclusion",id:"conclusion",level:2}],p={toc:m},u="wrapper";function d(e){let{components:t,...n}=e;return(0,i.yg)(u,(0,a.A)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,i.yg)("h1",{id:"time"},"TIME"),(0,i.yg)("p",null,"In GlueSQL, the ",(0,i.yg)("inlineCode",{parentName:"p"},"TIME")," data type is used to store time values in the format 'HH:MM:SS.SSS'. The code snippet provided demonstrates how to create a table with ",(0,i.yg)("inlineCode",{parentName:"p"},"TIME")," columns, insert data into it, and perform various queries and operations on the data."),(0,i.yg)("h2",{id:"creating-a-table-with-time-columns"},"Creating a table with TIME columns"),(0,i.yg)("p",null,"To create a table with columns of type ",(0,i.yg)("inlineCode",{parentName:"p"},"TIME"),", use the ",(0,i.yg)("inlineCode",{parentName:"p"},"CREATE TABLE")," statement:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-sql"},"CREATE TABLE TimeLog (\n id INTEGER,\n time1 TIME,\n time2 TIME\n);\n")),(0,i.yg)("h2",{id:"inserting-data-into-a-table-with-time-columns"},"Inserting data into a table with TIME columns"),(0,i.yg)("p",null,"To insert data into a table with ",(0,i.yg)("inlineCode",{parentName:"p"},"TIME")," columns, use the ",(0,i.yg)("inlineCode",{parentName:"p"},"INSERT INTO")," statement:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO TimeLog VALUES\n (1, '12:30:00', '13:31:01.123'),\n (2, '9:2:1', 'AM 08:02:01.001'),\n (3, 'PM 2:59', '9:00:00 AM');\n")),(0,i.yg)("h2",{id:"querying-data-from-a-table-with-time-columns"},"Querying data from a table with TIME columns"),(0,i.yg)("p",null,"To query data from a table with ",(0,i.yg)("inlineCode",{parentName:"p"},"TIME")," columns, use the ",(0,i.yg)("inlineCode",{parentName:"p"},"SELECT")," statement:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT id, time1, time2 FROM TimeLog;\n")),(0,i.yg)("h2",{id:"filtering-data-using-time-columns"},"Filtering data using TIME columns"),(0,i.yg)("p",null,"You can use various comparison operators like ",(0,i.yg)("inlineCode",{parentName:"p"},">"),", ",(0,i.yg)("inlineCode",{parentName:"p"},"<"),", ",(0,i.yg)("inlineCode",{parentName:"p"},"<="),", ",(0,i.yg)("inlineCode",{parentName:"p"},">="),", and ",(0,i.yg)("inlineCode",{parentName:"p"},"=")," to filter data based on ",(0,i.yg)("inlineCode",{parentName:"p"},"TIME")," columns:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT * FROM TimeLog WHERE time1 > time2;\n\nSELECT * FROM TimeLog WHERE time1 <= time2;\n\nSELECT * FROM TimeLog WHERE time1 = TIME '14:59:00';\n\nSELECT * FROM TimeLog WHERE time1 < '1:00 PM';\n")),(0,i.yg)("h2",{id:"performing-time-arithmetic"},"Performing time arithmetic"),(0,i.yg)("p",null,"You can perform arithmetic operations on ",(0,i.yg)("inlineCode",{parentName:"p"},"TIME")," columns using ",(0,i.yg)("inlineCode",{parentName:"p"},"INTERVAL"),":"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT\n id,\n time1 - time2 AS time_sub,\n time1 + INTERVAL '1' HOUR AS add,\n time2 - INTERVAL '250' MINUTE AS sub\nFROM TimeLog;\n")),(0,i.yg)("p",null,"You can also add a ",(0,i.yg)("inlineCode",{parentName:"p"},"TIME")," column to a ",(0,i.yg)("inlineCode",{parentName:"p"},"DATE")," value to get a ",(0,i.yg)("inlineCode",{parentName:"p"},"TIMESTAMP")," result:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-sql"},"SELECT\n id,\n DATE '2021-01-05' + time2 AS timestamp\nFROM TimeLog LIMIT 1;\n")),(0,i.yg)("h2",{id:"handling-invalid-time-values"},"Handling invalid time values"),(0,i.yg)("p",null,"If you try to insert an invalid time value into a ",(0,i.yg)("inlineCode",{parentName:"p"},"TIME")," column, GlueSQL will return an error:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre",className:"language-sql"},"INSERT INTO TimeLog VALUES (1, '12345-678', '20:05:01');\n")),(0,i.yg)("p",null,"This will result in an error similar to the following:"),(0,i.yg)("pre",null,(0,i.yg)("code",{parentName:"pre"},"failed to parse time 12345-678\n")),(0,i.yg)("h2",{id:"conclusion"},"Conclusion"),(0,i.yg)("p",null,"In GlueSQL, the TIME data type is used to store time values in the format 'HH:MM:SS.SSS'. The provided code snippet demonstrates how to create a table with TIME columns, insert data into it, and perform various queries and operations on the data. GlueSQL supports arithmetic operations on TIME columns using INTERVAL, and you can also add a TIME column to a DATE value to get a TIMESTAMP result. Keep in mind that inserting invalid time values into a TIME column will result in an error."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/main.d2f0168d.js b/docs/0.16.0/assets/js/main.d2f0168d.js new file mode 100644 index 00000000..2927a35c --- /dev/null +++ b/docs/0.16.0/assets/js/main.d2f0168d.js @@ -0,0 +1,2 @@ +/*! For license information please see main.d2f0168d.js.LICENSE.txt */ +(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[8792],{8328:(e,t,n)=>{"use strict";n.d(t,{A:()=>p});var a=n(6540),r=n(8168),o=n(3259),s=n.n(o),i=n(4054);const l={"007e0817":[()=>n.e(3631).then(n.bind(n,3697)),"@site/docs/sql-syntax/functions/text/ltrim.md",3697],"017e736e":[()=>n.e(5183).then(n.bind(n,7915)),"@site/docs/ast-builder/statements/querying/creating-derived-subqueries.md",7915],"01a12966":[()=>n.e(79).then(n.bind(n,6498)),"@site/docs/getting-started/nodejs.md",6498],"01a85c17":[()=>Promise.all([n.e(1869),n.e(8209)]).then(n.bind(n,9158)),"@theme/BlogTagsListPage",9158],"02aa4531":[()=>n.e(126).then(n.bind(n,8022)),"@site/docs/ast-builder/functions/math/conversion.md",8022],"02bfc02d":[()=>n.e(6858).then(n.bind(n,8356)),"@site/docs/ast-builder/functions/text/trimming.md",8356],"037683de":[()=>n.e(1661).then(n.bind(n,3550)),"@site/docs/ast-builder/statements/data-manipulation/updating-data.md",3550],"045be9fd":[()=>n.e(106).then(n.t.bind(n,2431,19)),"~blog/default/docs-0-16-0-blog-tags-sql-e39-list.json",2431],"0544f90b":[()=>n.e(1219).then(n.bind(n,2086)),"@site/docs/sql-syntax/statements/data-definition/create-index.md",2086],"06322d53":[()=>n.e(4972).then(n.bind(n,2239)),"@site/docs/sql-syntax/functions/text/initcap.md",2239],"07294b24":[()=>n.e(3055).then(n.bind(n,5332)),"@site/docs/ast-builder/functions/text/padding.md",5332],"078a6308":[()=>n.e(5732).then(n.bind(n,4228)),"@site/docs/ast-builder/functions/others/null-handling.md",4228],"0b621d16":[()=>n.e(8059).then(n.bind(n,9155)),"@site/docs/sql-syntax/data-types/decimal.md",9155],"0c18287f":[()=>n.e(2758).then(n.bind(n,2545)),"@site/docs/sql-syntax/functions/list-map/append.md",2545],"0c94c658":[()=>n.e(4887).then(n.bind(n,9326)),"@site/docs/sql-syntax/statements/data-definition/alter-table.md",9326],"0ea64360":[()=>n.e(7814).then(n.bind(n,2224)),"@site/docs/sql-syntax/functions/others/generate-uuid.md",2224],"104749c9":[()=>n.e(7662).then(n.t.bind(n,9543,19)),"~blog/default/docs-0-16-0-blog-tags-release-note-67b-list.json",9543],"107910e9":[()=>n.e(7637).then(n.t.bind(n,2879,19)),"~blog/default/docs-0-16-0-blog-tags-test-driven-documentation-8a1.json",2879],"15868c40":[()=>n.e(6528).then(n.bind(n,3682)),"@site/docs/sql-syntax/functions/text/position.md",3682],"160faf1d":[()=>n.e(2570).then(n.bind(n,2774)),"@site/docs/sql-syntax/functions/math/radians.md",2774],"16682cd3":[()=>n.e(5138).then(n.t.bind(n,9417,19)),"~blog/default/docs-0-16-0-blog-tags-automation-847.json",9417],"16815c2a":[()=>n.e(5380).then(n.bind(n,7482)),"@site/docs/ast-builder/statements/querying/data-sorting-and-limiting.md",7482],17896441:[()=>Promise.all([n.e(1869),n.e(8809),n.e(8401)]).then(n.bind(n,5022)),"@theme/DocItem",5022],"1798d0b3":[()=>n.e(6585).then(n.bind(n,3277)),"@site/docs/sql-syntax/data-types/bytea.md",3277],"194e858c":[()=>n.e(4234).then(n.bind(n,553)),"@site/docs/storages/developing-custom-storages/store-traits/alter-table.md",553],"1a3daba8":[()=>n.e(4726).then(n.bind(n,4924)),"@site/docs/sql-syntax/functions/geometry/point.md",4924],"1b8ca8c3":[()=>n.e(3772).then(n.bind(n,6478)),"@site/docs/sql-syntax/functions/math/floor.md",6478],"1be78505":[()=>Promise.all([n.e(1869),n.e(8714)]).then(n.bind(n,10)),"@theme/DocPage",10],"1c41eae2":[()=>n.e(1717).then(n.t.bind(n,2945,19)),"/home/runner/work/gluesql/gluesql/docs/.docusaurus/docusaurus-plugin-content-blog/default/plugin-route-context-module-100.json",2945],"1c93e70c":[()=>n.e(6276).then(n.bind(n,4687)),"@site/docs/getting-started/cli.md",4687],"1cdac986":[()=>n.e(7248).then(n.bind(n,3166)),"@site/docs/ast-builder/functions/text/text-manipulation.md",3166],"1ce64703":[()=>n.e(390).then(n.bind(n,834)),"@site/docs/ast-builder/functions/math/rounding.md",834],"1e4e1fb6":[()=>n.e(7889).then(n.t.bind(n,1966,19)),"/home/runner/work/gluesql/gluesql/docs/.docusaurus/docusaurus-plugin-content-docs/default/plugin-route-context-module-100.json",1966],"20e2ece2":[()=>n.e(9957).then(n.bind(n,274)),"@site/blog/2023-05-30-revolutionizing-databases-by-unifying-query-interfaces.md?truncated=true",274],"2149662b":[()=>n.e(1553).then(n.t.bind(n,8125,19)),"~blog/default/docs-0-16-0-blog-tags-tdd-106-list.json",8125],"234733fd":[()=>n.e(8053).then(n.bind(n,5122)),"@site/blog/2023-05-27-release-v0.14.md",5122],"23f93eeb":[()=>n.e(5120).then(n.bind(n,6694)),"@site/blog/2023-05-27-release-v0.14.md?truncated=true",6694],25196878:[()=>n.e(2997).then(n.bind(n,5309)),"@site/blog/2023-05-30-test-driven-documentation.md",5309],"26c0a43c":[()=>n.e(8799).then(n.bind(n,9710)),"@site/docs/ast-builder/functions/others/type-conversion.md",9710],"29fadaa3":[()=>n.e(4550).then(n.t.bind(n,4736,19)),"~blog/default/docs-0-16-0-blog-tags-release-note-67b.json",4736],"2a4d41ed":[()=>n.e(5062).then(n.bind(n,2184)),"@site/docs/sql-syntax/functions/geometry/get-y.md",2184],"2b265210":[()=>n.e(6257).then(n.bind(n,4509)),"@site/docs/ast-builder/expressions/pattern-matching.md",4509],"2bb892db":[()=>n.e(1990).then(n.t.bind(n,437,19)),"~blog/default/docs-0-16-0-blog-tags-v-0-14-51a.json",437],"2c0d2b92":[()=>n.e(8819).then(n.bind(n,590)),"@site/docs/sql-syntax/data-types/list.md",590],"2d9479c4":[()=>n.e(1459).then(n.bind(n,3072)),"@site/docs/sql-syntax/statements/querying/where.md",3072],"2f7bd5c8":[()=>n.e(3848).then(n.bind(n,1471)),"@site/docs/sql-syntax/functions/math/cos.md",1471],"31526b20":[()=>n.e(2920).then(n.bind(n,9773)),"@site/docs/sql-syntax/intro.md",9773],"3245f64b":[()=>n.e(9327).then(n.bind(n,7965)),"@site/docs/sql-syntax/statements/querying/aggregation.md",7965],"345c600d":[()=>n.e(8).then(n.bind(n,3368)),"@site/docs/storages/developing-custom-storages/using-test-suite.md",3368],"376759eb":[()=>n.e(3995).then(n.bind(n,9664)),"@site/docs/ast-builder/statements/data-manipulation/deleting-data.md",9664],"382b9f11":[()=>n.e(9445).then(n.t.bind(n,5368,19)),"~blog/default/docs-0-16-0-blog-tags-gluesql-8f6.json",5368],"385623dc":[()=>n.e(521).then(n.bind(n,4741)),"@site/docs/sql-syntax/functions/math/rand.md",4741],"3961e600":[()=>n.e(9565).then(n.bind(n,1279)),"@site/docs/storages/supported-storages/json-storage.md",1279],"3cfbc8af":[()=>n.e(7433).then(n.bind(n,5271)),"@site/docs/ast-builder/functions/text/character-conversion.md",5271],"3ee3a370":[()=>n.e(5010).then(n.t.bind(n,3750,19)),"~blog/default/docs-0-16-0-blog-tags-tdd-106.json",3750],"402da695":[()=>n.e(770).then(n.bind(n,7799)),"@site/docs/sql-syntax/statements/data-definition/drop-table.md",7799],41718851:[()=>n.e(7096).then(n.bind(n,933)),"@site/docs/sql-syntax/functions/text/trim.md",933],"425cb3cb":[()=>n.e(8707).then(n.t.bind(n,5967,19)),"~blog/default/docs-0-16-0-blog-tags-gluesql-8f6-list.json",5967],44954150:[()=>n.e(2323).then(n.bind(n,8801)),"@site/docs/ast-builder/expressions/operator-based.md",8801],"44f79c8d":[()=>n.e(550).then(n.bind(n,5846)),"@site/docs/storages/developing-custom-storages/store-traits/custom-function-mut.md",5846],"46076c8b":[()=>n.e(5169).then(n.t.bind(n,6447,19)),"~blog/default/docs-0-16-0-blog-b38.json",6447],"463dc00f":[()=>n.e(4303).then(n.bind(n,1854)),"@site/docs/ast-builder/functions/date-&-time/formatting.md",1854],"47e70afa":[()=>n.e(4082).then(n.t.bind(n,363,19)),"~blog/default/docs-0-16-0-blog-tags-nosql-2eb.json",363],"482a391c":[()=>n.e(1416).then(n.bind(n,6573)),"@site/docs/storages/developing-custom-storages/store-traits/store.md",6573],"488157d7":[()=>n.e(6061).then(n.bind(n,3568)),"@site/docs/storages/developing-custom-storages/store-traits/transaction.md",3568],"4a9d0f4c":[()=>n.e(9040).then(n.bind(n,6404)),"@site/docs/sql-syntax/functions/math/mod.md",6404],"4aa001c0":[()=>n.e(8317).then(n.bind(n,3527)),"@site/docs/sql-syntax/statements/data-definition/drop-index.md",3527],"4add0c6c":[()=>n.e(9564).then(n.bind(n,6721)),"@site/docs/ast-builder/intro.md",6721],"4be897c9":[()=>n.e(9350).then(n.bind(n,1247)),"@site/docs/ast-builder/statements/querying/data-injection.md",1247],"4d9df5b1":[()=>n.e(7540).then(n.bind(n,7849)),"@site/docs/sql-syntax/functions/list-map/splice.md",7849],"4f675ae9":[()=>n.e(4784).then(n.bind(n,362)),"@site/docs/sql-syntax/functions/datetime/extract.md",362],"5058a078":[()=>n.e(8505).then(n.bind(n,3103)),"@site/blog/2023-05-30-test-driven-documentation.md?truncated=true",3103],50818478:[()=>n.e(6088).then(n.bind(n,6022)),"@site/docs/sql-syntax/data-types/map.md",6022],"5242ac2d":[()=>n.e(4222).then(n.bind(n,5088)),"@site/docs/sql-syntax/functions/math/sqrt.md",5088],"56ccfc32":[()=>n.e(6098).then(n.bind(n,9023)),"@site/docs/sql-syntax/functions/math/ceil.md",9023],"575d1ad6":[()=>n.e(9700).then(n.t.bind(n,1224,19)),"~blog/default/docs-0-16-0-blog-archive-7ff.json",1224],"5a8c7729":[()=>n.e(4667).then(n.bind(n,3672)),"@site/docs/sql-syntax/functions/math/abs.md",3672],"5cdfb1f2":[()=>n.e(4386).then(n.bind(n,5799)),"@site/docs/storages/developing-custom-storages/store-traits/index-mut.md",5799],"5df6e7df":[()=>n.e(7514).then(n.bind(n,1308)),"@site/docs/ast-builder/expressions/nested.md",1308],"5eabd930":[()=>n.e(9612).then(n.bind(n,8607)),"@site/docs/sql-syntax/functions/text/right.md",8607],"67d1434e":[()=>n.e(4845).then(n.bind(n,4418)),"@site/docs/storages/supported-storages/composite-storage.md",4418],"6870612e":[()=>n.e(4192).then(n.bind(n,9915)),"@site/docs/sql-syntax/functions/math/sign.md",9915],"6875c492":[()=>Promise.all([n.e(1869),n.e(8809),n.e(8382),n.e(4813)]).then(n.bind(n,3069)),"@theme/BlogTagsPostsPage",3069],"68c17ba1":[()=>n.e(1296).then(n.bind(n,6837)),"@site/docs/sql-syntax/functions/math/asin.md",6837],"6a35a4d8":[()=>n.e(8439).then(n.bind(n,2425)),"@site/docs/storages/supported-storages/csv-storage.md",2425],"6ba4a510":[()=>n.e(3117).then(n.bind(n,7644)),"@site/docs/sql-syntax/functions/math/acos.md",7644],"6c5232c2":[()=>n.e(7135).then(n.bind(n,8661)),"@site/docs/sql-syntax/statements/metadata/data-dictionary.md",8661],"6d2a6c9a":[()=>n.e(285).then(n.t.bind(n,644,19)),"~blog/default/docs-0-16-0-blog-tags-query-interface-32a-list.json",644],"6e772156":[()=>n.e(108).then(n.bind(n,162)),"@site/docs/storages/supported-storages/memory-storage.md",162],"6ff6e7c9":[()=>n.e(1747).then(n.bind(n,1651)),"@site/docs/sql-syntax/data-types/interval.md",1651],"723607d1":[()=>n.e(7297).then(n.t.bind(n,2095,19)),"~blog/default/docs-0-16-0-blog-tags-documentation-a1a-list.json",2095],"72c409f7":[()=>n.e(4229).then(n.bind(n,7635)),"@site/docs/getting-started/rust.md",7635],"7310a4fe":[()=>n.e(3826).then(n.bind(n,6493)),"@site/docs/sql-syntax/statements/querying/schemaless.md",6493],"7457c448":[()=>n.e(827).then(n.bind(n,6062)),"@site/docs/sql-syntax/functions/text/rpad.md",6062],"7538b401":[()=>n.e(9309).then(n.t.bind(n,7560,19)),"~blog/default/docs-0-16-0-blog-tags-documentation-a1a.json",7560],"75880d90":[()=>n.e(3268).then(n.t.bind(n,4084,19)),"~blog/default/docs-0-16-0-blog-tags-tags-990.json",4084],"76bcd116":[()=>n.e(6637).then(n.t.bind(n,8764,19)),"~blog/default/docs-0-16-0-blog-tags-proposal-601.json",8764],"772fc39d":[()=>n.e(6704).then(n.bind(n,8414)),"@site/blog/2023-05-30-revolutionizing-databases-by-unifying-query-interfaces.md",8414],"77cc432a":[()=>n.e(6867).then(n.bind(n,3105)),"@site/docs/sql-syntax/functions/list-map/prepend.md",3105],"7d170ab0":[()=>n.e(969).then(n.bind(n,7213)),"@site/blog/2023-05-29-breaking-the-boundary.md",7213],"7e0ce508":[()=>n.e(7722).then(n.bind(n,1196)),"@site/docs/sql-syntax/functions/math/round.md",1196],"7ea7f008":[()=>n.e(4217).then(n.bind(n,3085)),"@site/docs/ast-builder/functions/date-&-time/date-and-time-extraction.md",3085],"7f479c52":[()=>n.e(9070).then(n.t.bind(n,8,19)),"~blog/default/docs-0-16-0-blog-tags-automation-847-list.json",8],"814f3328":[()=>n.e(7472).then(n.t.bind(n,5513,19)),"~blog/default/blog-post-list-prop-default.json",5513],"81bf07f5":[()=>n.e(1978).then(n.bind(n,2038)),"@site/docs/ast-builder/functions/list-&-map/list-and-map-concatenation.md",2038],"81f6aa2c":[()=>n.e(9033).then(n.bind(n,9032)),"@site/docs/sql-syntax/functions/text/lower.md",9032],"83b912d4":[()=>n.e(6826).then(n.bind(n,1622)),"@site/docs/storages/developing-custom-storages/store-traits/custom-function.md",1622],"8417e7a5":[()=>n.e(8681).then(n.bind(n,7775)),"@site/blog/2023-05-29-breaking-the-boundary.md?truncated=true",7775],"85afcbde":[()=>n.e(2605).then(n.bind(n,2659)),"@site/docs/sql-syntax/functions/math/tan.md",2659],"86a1f821":[()=>n.e(9186).then(n.bind(n,7810)),"@site/docs/sql-syntax/statements/data-definition/create-table.md",7810],"89196f72":[()=>n.e(6995).then(n.bind(n,4856)),"@site/docs/ast-builder/functions/math/special-mathematical.md",4856],"89fc5f00":[()=>n.e(4646).then(n.bind(n,5559)),"@site/docs/ast-builder/functions/geometry/distance-calculation.md",5559],"8be9dc67":[()=>n.e(5773).then(n.bind(n,8882)),"@site/docs/sql-syntax/statements/data-manipulation/update.md",8882],"8c7569e5":[()=>n.e(6205).then(n.bind(n,2715)),"@site/docs/ast-builder/functions/date-&-time/current-date-and-time.md",2715],"8cf2dd9c":[()=>n.e(2636).then(n.bind(n,978)),"@site/docs/sql-syntax/functions/text/chr.md",978],"8d6e802b":[()=>n.e(2468).then(n.bind(n,4515)),"@site/docs/storages/supported-storages/sled-storage.md",4515],"920bdc78":[()=>n.e(666).then(n.bind(n,6307)),"@site/docs/sql-syntax/functions/math/div.md",6307],"928a5d6f":[()=>n.e(6576).then(n.bind(n,7995)),"@site/docs/sql-syntax/functions/datetime/to-date.md",7995],"92dd0956":[()=>n.e(5086).then(n.bind(n,5480)),"@site/docs/sql-syntax/statements/data-manipulation/delete.md",5480],"935f2afb":[()=>n.e(8581).then(n.t.bind(n,5610,19)),"~docs/default/version-current-metadata-prop-751.json",5610],"952dfacb":[()=>n.e(6571).then(n.bind(n,4552)),"@site/docs/storages/supported-storages/idb-storage.md",4552],"97081ee7":[()=>n.e(7033).then(n.bind(n,5316)),"@site/docs/sql-syntax/functions/text/lpad.md",5316],"980f8d5e":[()=>n.e(4848).then(n.bind(n,7605)),"@site/docs/ast-builder/functions/math/logarithmic-and-exponential.md",7605],98184455:[()=>n.e(4541).then(n.t.bind(n,8419,19)),"~blog/default/docs-0-16-0-blog-tags-proposal-601-list.json",8419],"98306a23":[()=>n.e(5535).then(n.bind(n,7835)),"@site/docs/sql-syntax/functions/datetime/now.md",7835],"9a1c8bc6":[()=>n.e(5760).then(n.bind(n,4414)),"@site/docs/sql-syntax/functions/math/sin.md",4414],"9a3e57da":[()=>n.e(3216).then(n.bind(n,5887)),"@site/docs/sql-syntax/functions/geometry/get-x.md",5887],"9c5158ac":[()=>n.e(6926).then(n.bind(n,3079)),"@site/docs/ast-builder/functions/math/basic-arithmetic.md",3079],"9c7b888e":[()=>n.e(1489).then(n.t.bind(n,3441,19)),"~blog/default/docs-0-16-0-blog-tags-database-017-list.json",3441],"9e4087bc":[()=>n.e(2711).then(n.bind(n,9331)),"@theme/BlogArchivePage",9331],"9edb318c":[()=>n.e(8032).then(n.t.bind(n,8174,19)),"~blog/default/docs-0-16-0-blog-tags-test-driven-documentation-8a1-list.json",8174],a2ab2bad:[()=>n.e(732).then(n.bind(n,3184)),"@site/docs/ast-builder/functions/list-&-map/list-manipulation.md",3184],a470b55c:[()=>n.e(8242).then(n.bind(n,5833)),"@site/docs/sql-syntax/functions/text/concat.md",5833],a4bc1622:[()=>n.e(1656).then(n.bind(n,6859)),"@site/docs/ast-builder/expressions/conditional.md",6859],a5971d1a:[()=>n.e(3892).then(n.bind(n,842)),"@site/docs/sql-syntax/data-types/date.md",842],a6aa9e1f:[()=>Promise.all([n.e(1869),n.e(8809),n.e(8382),n.e(7643)]).then(n.bind(n,7785)),"@theme/BlogListPage",7785],a6b6486c:[()=>n.e(3823).then(n.bind(n,4492)),"@site/docs/ast-builder/functions/geometry/point-creation.md",4492],a7153b78:[()=>n.e(3071).then(n.bind(n,6162)),"@site/docs/sql-syntax/functions/datetime/to-time.md",6162],a7e6874c:[()=>n.e(8738).then(n.bind(n,5653)),"@site/docs/sql-syntax/functions/math/power.md",5653],a87d47f1:[()=>n.e(133).then(n.t.bind(n,4068,19)),"~blog/default/docs-0-16-0-blog-tags-v-0-14-51a-list.json",4068],a8d11699:[()=>n.e(5834).then(n.bind(n,7136)),"@site/docs/sql-syntax/data-types/timestamp.md",7136],a9e26133:[()=>n.e(4073).then(n.bind(n,8760)),"@site/docs/sql-syntax/data-types/inet.md",8760],aa1cf9a2:[()=>n.e(5363).then(n.bind(n,93)),"@site/docs/sql-syntax/data-types/integers.md",93],acfabe81:[()=>n.e(2450).then(n.bind(n,5490)),"@site/docs/ast-builder/functions/date-&-time/conversion.md",5490],ae3eef3e:[()=>n.e(2591).then(n.bind(n,4060)),"@site/docs/sql-syntax/functions/math/ln.md",4060],ae967838:[()=>n.e(9876).then(n.bind(n,9947)),"@site/docs/sql-syntax/functions/text/reverse.md",9947],afebe5f1:[()=>n.e(1838).then(n.bind(n,3927)),"@site/docs/sql-syntax/functions/math/log10.md",3927],aff456d7:[()=>n.e(2710).then(n.bind(n,4685)),"@site/docs/sql-syntax/functions/geometry/calc-distance.md",4685],b209ab8a:[()=>n.e(3386).then(n.bind(n,6719)),"@site/docs/storages/intro.md",6719],b3de9677:[()=>n.e(7319).then(n.bind(n,1624)),"@site/docs/ast-builder/statements/querying/data-aggregation.md",1624],b57ca7d5:[()=>n.e(7879).then(n.bind(n,4374)),"@site/docs/sql-syntax/functions/text/repeat.md",4374],b6bceaff:[()=>n.e(2012).then(n.bind(n,535)),"@site/docs/ast-builder/expressions/value-checking.md",535],b7661aba:[()=>n.e(3783).then(n.bind(n,1749)),"@site/docs/sql-syntax/functions/text/upper.md",1749],b7da1136:[()=>n.e(4602).then(n.bind(n,7960)),"@site/docs/sql-syntax/statements/querying/limit.md",7960],ba43b2d5:[()=>n.e(6554).then(n.bind(n,6644)),"@site/docs/sql-syntax/functions/math/atan.md",6644],bac2c42d:[()=>n.e(8604).then(n.bind(n,1829)),"@site/docs/ast-builder/statements/data-manipulation/inserting-data.md",1829],bb43b8ce:[()=>n.e(5006).then(n.bind(n,5810)),"@site/docs/sql-syntax/functions/others/cast.md",5810],bfb64759:[()=>n.e(7794).then(n.bind(n,2029)),"@site/docs/sql-syntax/data-types/uuid.md",2029],c251e734:[()=>n.e(7179).then(n.bind(n,5926)),"@site/docs/storages/developing-custom-storages/intro.md",5926],c2e5ab4f:[()=>n.e(2245).then(n.bind(n,8535)),"@site/docs/sql-syntax/functions/datetime/to-timestamp.md",8535],c30ee527:[()=>n.e(6204).then(n.bind(n,351)),"@site/docs/sql-syntax/statements/metadata/show-tables.md",351],c34cc4c9:[()=>n.e(5427).then(n.t.bind(n,5484,19)),"~blog/default/docs-0-16-0-blog-tags-chat-gpt-ad2.json",5484],c377a04b:[()=>n.e(5742).then(n.bind(n,1866)),"@site/docs/index.md",1866],c3b79ba0:[()=>n.e(1570).then(n.t.bind(n,3786,19)),"~blog/default/docs-0-16-0-blog-tags-nosql-2eb-list.json",3786],c5b25a7c:[()=>n.e(6247).then(n.bind(n,7516)),"@site/docs/sql-syntax/functions/text/concat-ws.md",7516],c5c08033:[()=>n.e(2100).then(n.bind(n,2172)),"@site/blog/2023-11-18-release-v0.15.md",2172],c5e834bc:[()=>n.e(7700).then(n.bind(n,5476)),"@site/docs/ast-builder/functions/math/trigonometric.md",5476],c97e0540:[()=>n.e(8590).then(n.bind(n,9573)),"@site/docs/sql-syntax/functions/math/degrees.md",9573],c9d1eb08:[()=>n.e(2119).then(n.bind(n,8315)),"@site/docs/sql-syntax/functions/text/rtrim.md",8315],ca8fbf24:[()=>n.e(7807).then(n.t.bind(n,8707,19)),"~blog/default/docs-0-16-0-blog-tags-chat-gpt-ad2-list.json",8707],cba69ead:[()=>n.e(9544).then(n.t.bind(n,7350,19)),"~blog/default/docs-0-16-0-blog-tags-v-0-15-9a2-list.json",7350],ccc49370:[()=>Promise.all([n.e(1869),n.e(8809),n.e(8382),n.e(3249)]).then(n.bind(n,4029)),"@theme/BlogPostPage",4029],cdaafcc9:[()=>n.e(1433).then(n.bind(n,5682)),"@site/docs/sql-syntax/functions/math/gcd.md",5682],cf518063:[()=>n.e(6251).then(n.bind(n,8065)),"@site/docs/sql-syntax/functions/list-map/concat.md",8065],d077f377:[()=>n.e(6738).then(n.bind(n,3433)),"@site/docs/sql-syntax/data-types/text.md",3433],d0ba620f:[()=>n.e(5334).then(n.bind(n,6103)),"@site/docs/sql-syntax/functions/list-map/slice.md",6103],d4251823:[()=>n.e(1274).then(n.bind(n,2152)),"@site/docs/sql-syntax/functions/text/find-idx.md",2152],d5aa49f9:[()=>n.e(3274).then(n.bind(n,776)),"@site/docs/ast-builder/functions/others/unique-identifier.md",776],d7a493e6:[()=>n.e(5666).then(n.bind(n,318)),"@site/docs/ast-builder/functions/text/case-conversion.md",318],d8746e52:[()=>n.e(5e3).then(n.bind(n,2248)),"@site/docs/sql-syntax/functions/text/substr.md",2248],d941076d:[()=>n.e(262).then(n.bind(n,6078)),"@site/docs/storages/developing-custom-storages/store-traits/index-trait.md",6078],d97b7d4d:[()=>n.e(3352).then(n.bind(n,4351)),"@site/docs/ast-builder/statements/querying/using-preloaded-data.md",4351],dafe2799:[()=>n.e(1202).then(n.bind(n,9324)),"@site/docs/sql-syntax/functions/text/left.md",9324],db0d9cb2:[()=>n.e(129).then(n.bind(n,394)),"@site/docs/sql-syntax/functions/math/log.md",394],dc8f2f6c:[()=>n.e(2735).then(n.bind(n,2143)),"@site/docs/sql-syntax/statements/querying/join.md",2143],dd9db7c1:[()=>n.e(3497).then(n.t.bind(n,581,19)),"~blog/default/docs-0-16-0-blog-tags-query-interface-32a.json",581],df2eb7da:[()=>n.e(1502).then(n.bind(n,498)),"@site/docs/sql-syntax/statements/data-manipulation/insert.md",498],e06425d1:[()=>n.e(4704).then(n.bind(n,5706)),"@site/docs/sql-syntax/functions/text/ascii.md",5706],e10f7c24:[()=>n.e(6803).then(n.bind(n,7365)),"@site/docs/getting-started/javascript-web.md",7365],e158c27a:[()=>n.e(321).then(n.bind(n,7914)),"@site/docs/sql-syntax/statements/transaction.md",7914],e329d2fa:[()=>n.e(805).then(n.bind(n,5323)),"@site/docs/storages/developing-custom-storages/store-traits/metadata.md",5323],e46b95eb:[()=>n.e(2883).then(n.bind(n,5618)),"@site/docs/storages/supported-storages/shared-memory-storage.md",5618],e4f709d1:[()=>n.e(4253).then(n.bind(n,2864)),"@site/docs/sql-syntax/functions/math/lcm.md",2864],e5f53749:[()=>n.e(8465).then(n.bind(n,7790)),"@site/docs/ast-builder/statements/querying/data-joining.md",7790],e68f8ad6:[()=>n.e(1947).then(n.bind(n,2944)),"@site/docs/sql-syntax/data-types/boolean.md",2944],ebe12d94:[()=>n.e(2025).then(n.bind(n,6930)),"@site/docs/storages/developing-custom-storages/store-traits/store-mut.md",6930],ec040517:[()=>n.e(7458).then(n.t.bind(n,6664,19)),"~blog/default/docs-0-16-0-blog-tags-sql-e39.json",6664],ec49082b:[()=>n.e(306).then(n.t.bind(n,9354,19)),"~blog/default/docs-0-16-0-blog-tags-database-017.json",9354],eceb3b9b:[()=>n.e(7436).then(n.bind(n,457)),"@site/docs/sql-syntax/functions/math/pi.md",457],edb9b0b8:[()=>n.e(4467).then(n.bind(n,6539)),"@site/docs/storages/supported-storages/web-storage.md",6539],ee244d12:[()=>n.e(1226).then(n.bind(n,2853)),"@site/docs/ast-builder/statements/querying/fetching-data-from-storage.md",2853],f11e9837:[()=>n.e(1007).then(n.t.bind(n,4871,19)),"~blog/default/docs-0-16-0-blog-tags-v-0-15-9a2.json",4871],f1257df2:[()=>n.e(7278).then(n.bind(n,1626)),"@site/docs/sql-syntax/functions/math/log2.md",1626],f18bbaf6:[()=>n.e(1485).then(n.bind(n,8072)),"@site/docs/sql-syntax/functions/datetime/format.md",8072],f33f2c05:[()=>n.e(7309).then(n.bind(n,6794)),"@site/docs/sql-syntax/data-types/float.md",6794],f6ca3de5:[()=>n.e(7532).then(n.bind(n,1046)),"@site/docs/ast-builder/functions/geometry/coordinate-extraction.md",1046],f7912ff8:[()=>n.e(6834).then(n.bind(n,2673)),"@site/docs/storages/supported-storages/parquet-storage.md",2673],f87e687e:[()=>n.e(9251).then(n.bind(n,3112)),"@site/blog/2023-11-18-release-v0.15.md?truncated=true",3112],f914cfe8:[()=>n.e(1403).then(n.bind(n,3124)),"@site/docs/ast-builder/statements/querying/data-selection-and-projection.md",3124],f9553497:[()=>n.e(2495).then(n.bind(n,3947)),"@site/docs/ast-builder/functions/text/position-and-indexing.md",3947],fa5466f2:[()=>n.e(3679).then(n.bind(n,7587)),"@site/docs/sql-syntax/functions/others/ifnull.md",7587],faca410e:[()=>n.e(2160).then(n.bind(n,4271)),"@site/docs/sql-syntax/functions/math/exp.md",4271],ff7b8d8e:[()=>n.e(85).then(n.bind(n,1088)),"@site/docs/sql-syntax/data-types/time.md",1088]};function c(e){let{error:t,retry:n,pastDelay:r}=e;return t?a.createElement("div",{style:{textAlign:"center",color:"#fff",backgroundColor:"#fa383e",borderColor:"#fa383e",borderStyle:"solid",borderRadius:"0.25rem",borderWidth:"1px",boxSizing:"border-box",display:"block",padding:"1rem",flex:"0 0 50%",marginLeft:"25%",marginRight:"25%",marginTop:"5rem",maxWidth:"50%",width:"100%"}},a.createElement("p",null,String(t)),a.createElement("div",null,a.createElement("button",{type:"button",onClick:n},"Retry"))):r?a.createElement("div",{style:{display:"flex",justifyContent:"center",alignItems:"center",height:"100vh"}},a.createElement("svg",{id:"loader",style:{width:128,height:110,position:"absolute",top:"calc(100vh - 64%)"},viewBox:"0 0 45 45",xmlns:"http://www.w3.org/2000/svg",stroke:"#61dafb"},a.createElement("g",{fill:"none",fillRule:"evenodd",transform:"translate(1 1)",strokeWidth:"2"},a.createElement("circle",{cx:"22",cy:"22",r:"6",strokeOpacity:"0"},a.createElement("animate",{attributeName:"r",begin:"1.5s",dur:"3s",values:"6;22",calcMode:"linear",repeatCount:"indefinite"}),a.createElement("animate",{attributeName:"stroke-opacity",begin:"1.5s",dur:"3s",values:"1;0",calcMode:"linear",repeatCount:"indefinite"}),a.createElement("animate",{attributeName:"stroke-width",begin:"1.5s",dur:"3s",values:"2;0",calcMode:"linear",repeatCount:"indefinite"})),a.createElement("circle",{cx:"22",cy:"22",r:"6",strokeOpacity:"0"},a.createElement("animate",{attributeName:"r",begin:"3s",dur:"3s",values:"6;22",calcMode:"linear",repeatCount:"indefinite"}),a.createElement("animate",{attributeName:"stroke-opacity",begin:"3s",dur:"3s",values:"1;0",calcMode:"linear",repeatCount:"indefinite"}),a.createElement("animate",{attributeName:"stroke-width",begin:"3s",dur:"3s",values:"2;0",calcMode:"linear",repeatCount:"indefinite"})),a.createElement("circle",{cx:"22",cy:"22",r:"8"},a.createElement("animate",{attributeName:"r",begin:"0s",dur:"1.5s",values:"6;1;2;3;4;5;6",calcMode:"linear",repeatCount:"indefinite"}))))):null}var u=n(6921),d=n(3102);function f(e,t){if("*"===e)return s()({loading:c,loader:()=>n.e(1774).then(n.bind(n,1774)),modules:["@theme/NotFound"],webpack:()=>[1774],render(e,t){const n=e.default;return a.createElement(d.W,{value:{plugin:{name:"native",id:"default"}}},a.createElement(n,t))}});const o=i[`${e}-${t}`],f={},p=[],m=[],g=(0,u.A)(o);return Object.entries(g).forEach((e=>{let[t,n]=e;const a=l[n];a&&(f[t]=a[0],p.push(a[1]),m.push(a[2]))})),s().Map({loading:c,loader:f,modules:p,webpack:()=>m,render(t,n){const s=JSON.parse(JSON.stringify(o));Object.entries(t).forEach((t=>{let[n,a]=t;const r=a.default;if(!r)throw new Error(`The page component at ${e} doesn't have a default export. This makes it impossible to render anything. Consider default-exporting a React component.`);"object"!=typeof r&&"function"!=typeof r||Object.keys(a).filter((e=>"default"!==e)).forEach((e=>{r[e]=a[e]}));let o=s;const i=n.split(".");i.slice(0,-1).forEach((e=>{o=o[e]})),o[i[i.length-1]]=r}));const i=s.__comp;delete s.__comp;const l=s.__context;return delete s.__context,a.createElement(d.W,{value:l},a.createElement(i,(0,r.A)({},s,n)))}})}const p=[{path:"/docs/0.16.0/blog",component:f("/docs/0.16.0/blog","329"),exact:!0},{path:"/docs/0.16.0/blog/archive",component:f("/docs/0.16.0/blog/archive","230"),exact:!0},{path:"/docs/0.16.0/blog/breaking-the-boundary-between-sql-and-nosql",component:f("/docs/0.16.0/blog/breaking-the-boundary-between-sql-and-nosql","ed2"),exact:!0},{path:"/docs/0.16.0/blog/release-v0.14",component:f("/docs/0.16.0/blog/release-v0.14","ae9"),exact:!0},{path:"/docs/0.16.0/blog/release-v0.15",component:f("/docs/0.16.0/blog/release-v0.15","628"),exact:!0},{path:"/docs/0.16.0/blog/revolutionizing-databases-by-unifying-query-interfaces",component:f("/docs/0.16.0/blog/revolutionizing-databases-by-unifying-query-interfaces","bfc"),exact:!0},{path:"/docs/0.16.0/blog/tags",component:f("/docs/0.16.0/blog/tags","a26"),exact:!0},{path:"/docs/0.16.0/blog/tags/automation",component:f("/docs/0.16.0/blog/tags/automation","b16"),exact:!0},{path:"/docs/0.16.0/blog/tags/chat-gpt",component:f("/docs/0.16.0/blog/tags/chat-gpt","44c"),exact:!0},{path:"/docs/0.16.0/blog/tags/database",component:f("/docs/0.16.0/blog/tags/database","ef3"),exact:!0},{path:"/docs/0.16.0/blog/tags/documentation",component:f("/docs/0.16.0/blog/tags/documentation","26a"),exact:!0},{path:"/docs/0.16.0/blog/tags/gluesql",component:f("/docs/0.16.0/blog/tags/gluesql","cad"),exact:!0},{path:"/docs/0.16.0/blog/tags/nosql",component:f("/docs/0.16.0/blog/tags/nosql","44a"),exact:!0},{path:"/docs/0.16.0/blog/tags/proposal",component:f("/docs/0.16.0/blog/tags/proposal","897"),exact:!0},{path:"/docs/0.16.0/blog/tags/query-interface",component:f("/docs/0.16.0/blog/tags/query-interface","958"),exact:!0},{path:"/docs/0.16.0/blog/tags/release-note",component:f("/docs/0.16.0/blog/tags/release-note","356"),exact:!0},{path:"/docs/0.16.0/blog/tags/sql",component:f("/docs/0.16.0/blog/tags/sql","0fc"),exact:!0},{path:"/docs/0.16.0/blog/tags/tdd",component:f("/docs/0.16.0/blog/tags/tdd","547"),exact:!0},{path:"/docs/0.16.0/blog/tags/test-driven-documentation",component:f("/docs/0.16.0/blog/tags/test-driven-documentation","bc0"),exact:!0},{path:"/docs/0.16.0/blog/tags/v-0-14",component:f("/docs/0.16.0/blog/tags/v-0-14","b27"),exact:!0},{path:"/docs/0.16.0/blog/tags/v-0-15",component:f("/docs/0.16.0/blog/tags/v-0-15","26e"),exact:!0},{path:"/docs/0.16.0/blog/test-driven-documentation",component:f("/docs/0.16.0/blog/test-driven-documentation","96f"),exact:!0},{path:"/docs/0.16.0/",component:f("/docs/0.16.0/","0d5"),routes:[{path:"/docs/0.16.0/",component:f("/docs/0.16.0/","c45"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/ast-builder/expressions/conditional",component:f("/docs/0.16.0/ast-builder/expressions/conditional","455"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/ast-builder/expressions/nested",component:f("/docs/0.16.0/ast-builder/expressions/nested","dec"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/ast-builder/expressions/operator-based",component:f("/docs/0.16.0/ast-builder/expressions/operator-based","f0e"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/ast-builder/expressions/pattern-matching",component:f("/docs/0.16.0/ast-builder/expressions/pattern-matching","027"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/ast-builder/expressions/value-checking",component:f("/docs/0.16.0/ast-builder/expressions/value-checking","53b"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/ast-builder/functions/date-&-time/conversion",component:f("/docs/0.16.0/ast-builder/functions/date-&-time/conversion","8cb"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/ast-builder/functions/date-&-time/current-date-and-time",component:f("/docs/0.16.0/ast-builder/functions/date-&-time/current-date-and-time","cc6"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/ast-builder/functions/date-&-time/date-and-time-extraction",component:f("/docs/0.16.0/ast-builder/functions/date-&-time/date-and-time-extraction","4a1"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/ast-builder/functions/date-&-time/formatting",component:f("/docs/0.16.0/ast-builder/functions/date-&-time/formatting","2e7"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/ast-builder/functions/geometry/coordinate-extraction",component:f("/docs/0.16.0/ast-builder/functions/geometry/coordinate-extraction","0b9"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/ast-builder/functions/geometry/distance-calculation",component:f("/docs/0.16.0/ast-builder/functions/geometry/distance-calculation","842"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/ast-builder/functions/geometry/point-creation",component:f("/docs/0.16.0/ast-builder/functions/geometry/point-creation","a22"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/ast-builder/functions/list-&-map/list-and-map-concatenation",component:f("/docs/0.16.0/ast-builder/functions/list-&-map/list-and-map-concatenation","fa4"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/ast-builder/functions/list-&-map/list-manipulation",component:f("/docs/0.16.0/ast-builder/functions/list-&-map/list-manipulation","ad0"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/ast-builder/functions/math/basic-arithmetic",component:f("/docs/0.16.0/ast-builder/functions/math/basic-arithmetic","e45"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/ast-builder/functions/math/conversion",component:f("/docs/0.16.0/ast-builder/functions/math/conversion","de5"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/ast-builder/functions/math/logarithmic-and-exponential",component:f("/docs/0.16.0/ast-builder/functions/math/logarithmic-and-exponential","047"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/ast-builder/functions/math/rounding",component:f("/docs/0.16.0/ast-builder/functions/math/rounding","430"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/ast-builder/functions/math/special-mathematical",component:f("/docs/0.16.0/ast-builder/functions/math/special-mathematical","06e"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/ast-builder/functions/math/trigonometric",component:f("/docs/0.16.0/ast-builder/functions/math/trigonometric","2f4"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/ast-builder/functions/others/null-handling",component:f("/docs/0.16.0/ast-builder/functions/others/null-handling","600"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/ast-builder/functions/others/type-conversion",component:f("/docs/0.16.0/ast-builder/functions/others/type-conversion","c9d"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/ast-builder/functions/others/unique-identifier",component:f("/docs/0.16.0/ast-builder/functions/others/unique-identifier","0db"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/ast-builder/functions/text/case-conversion",component:f("/docs/0.16.0/ast-builder/functions/text/case-conversion","51f"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/ast-builder/functions/text/character-conversion",component:f("/docs/0.16.0/ast-builder/functions/text/character-conversion","8df"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/ast-builder/functions/text/padding",component:f("/docs/0.16.0/ast-builder/functions/text/padding","a12"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/ast-builder/functions/text/position-and-indexing",component:f("/docs/0.16.0/ast-builder/functions/text/position-and-indexing","24f"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/ast-builder/functions/text/text-manipulation",component:f("/docs/0.16.0/ast-builder/functions/text/text-manipulation","5fa"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/ast-builder/functions/text/trimming",component:f("/docs/0.16.0/ast-builder/functions/text/trimming","025"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/ast-builder/intro",component:f("/docs/0.16.0/ast-builder/intro","a6e"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/ast-builder/statements/data-manipulation/deleting-data",component:f("/docs/0.16.0/ast-builder/statements/data-manipulation/deleting-data","5a9"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/ast-builder/statements/data-manipulation/inserting-data",component:f("/docs/0.16.0/ast-builder/statements/data-manipulation/inserting-data","924"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/ast-builder/statements/data-manipulation/updating-data",component:f("/docs/0.16.0/ast-builder/statements/data-manipulation/updating-data","727"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/ast-builder/statements/querying/creating-derived-subqueries",component:f("/docs/0.16.0/ast-builder/statements/querying/creating-derived-subqueries","c6d"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/ast-builder/statements/querying/data-aggregation",component:f("/docs/0.16.0/ast-builder/statements/querying/data-aggregation","116"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/ast-builder/statements/querying/data-injection",component:f("/docs/0.16.0/ast-builder/statements/querying/data-injection","745"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/ast-builder/statements/querying/data-joining",component:f("/docs/0.16.0/ast-builder/statements/querying/data-joining","caf"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/ast-builder/statements/querying/data-selection-and-projection",component:f("/docs/0.16.0/ast-builder/statements/querying/data-selection-and-projection","88b"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/ast-builder/statements/querying/data-sorting-and-limiting",component:f("/docs/0.16.0/ast-builder/statements/querying/data-sorting-and-limiting","64f"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/ast-builder/statements/querying/fetching-data-from-storage",component:f("/docs/0.16.0/ast-builder/statements/querying/fetching-data-from-storage","1ed"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/ast-builder/statements/querying/using-preloaded-data",component:f("/docs/0.16.0/ast-builder/statements/querying/using-preloaded-data","ec8"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/getting-started/cli",component:f("/docs/0.16.0/getting-started/cli","2ff"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/getting-started/javascript-web",component:f("/docs/0.16.0/getting-started/javascript-web","040"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/getting-started/nodejs",component:f("/docs/0.16.0/getting-started/nodejs","af8"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/getting-started/rust",component:f("/docs/0.16.0/getting-started/rust","43e"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/data-types/boolean",component:f("/docs/0.16.0/sql-syntax/data-types/boolean","a91"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/data-types/bytea",component:f("/docs/0.16.0/sql-syntax/data-types/bytea","f2a"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/data-types/date",component:f("/docs/0.16.0/sql-syntax/data-types/date","b96"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/data-types/decimal",component:f("/docs/0.16.0/sql-syntax/data-types/decimal","0a5"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/data-types/float",component:f("/docs/0.16.0/sql-syntax/data-types/float","2cf"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/data-types/inet",component:f("/docs/0.16.0/sql-syntax/data-types/inet","f37"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/data-types/integers",component:f("/docs/0.16.0/sql-syntax/data-types/integers","173"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/data-types/interval",component:f("/docs/0.16.0/sql-syntax/data-types/interval","7c6"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/data-types/list",component:f("/docs/0.16.0/sql-syntax/data-types/list","438"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/data-types/map",component:f("/docs/0.16.0/sql-syntax/data-types/map","b8c"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/data-types/text",component:f("/docs/0.16.0/sql-syntax/data-types/text","2f3"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/data-types/time",component:f("/docs/0.16.0/sql-syntax/data-types/time","fb4"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/data-types/timestamp",component:f("/docs/0.16.0/sql-syntax/data-types/timestamp","62b"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/data-types/uuid",component:f("/docs/0.16.0/sql-syntax/data-types/uuid","ea3"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/datetime/extract",component:f("/docs/0.16.0/sql-syntax/functions/datetime/extract","5be"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/datetime/format",component:f("/docs/0.16.0/sql-syntax/functions/datetime/format","afd"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/datetime/now",component:f("/docs/0.16.0/sql-syntax/functions/datetime/now","17b"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/datetime/to-date",component:f("/docs/0.16.0/sql-syntax/functions/datetime/to-date","6b1"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/datetime/to-time",component:f("/docs/0.16.0/sql-syntax/functions/datetime/to-time","88f"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/datetime/to-timestamp",component:f("/docs/0.16.0/sql-syntax/functions/datetime/to-timestamp","168"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/geometry/calc-distance",component:f("/docs/0.16.0/sql-syntax/functions/geometry/calc-distance","e74"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/geometry/get-x",component:f("/docs/0.16.0/sql-syntax/functions/geometry/get-x","c71"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/geometry/get-y",component:f("/docs/0.16.0/sql-syntax/functions/geometry/get-y","9cc"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/geometry/point",component:f("/docs/0.16.0/sql-syntax/functions/geometry/point","0a6"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/list-map/append",component:f("/docs/0.16.0/sql-syntax/functions/list-map/append","3c6"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/list-map/concat",component:f("/docs/0.16.0/sql-syntax/functions/list-map/concat","8ee"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/list-map/prepend",component:f("/docs/0.16.0/sql-syntax/functions/list-map/prepend","104"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/list-map/slice",component:f("/docs/0.16.0/sql-syntax/functions/list-map/slice","ce3"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/list-map/splice",component:f("/docs/0.16.0/sql-syntax/functions/list-map/splice","1f9"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/math/abs",component:f("/docs/0.16.0/sql-syntax/functions/math/abs","ae9"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/math/acos",component:f("/docs/0.16.0/sql-syntax/functions/math/acos","2c5"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/math/asin",component:f("/docs/0.16.0/sql-syntax/functions/math/asin","9cb"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/math/atan",component:f("/docs/0.16.0/sql-syntax/functions/math/atan","ad4"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/math/ceil",component:f("/docs/0.16.0/sql-syntax/functions/math/ceil","6f8"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/math/cos",component:f("/docs/0.16.0/sql-syntax/functions/math/cos","776"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/math/degrees",component:f("/docs/0.16.0/sql-syntax/functions/math/degrees","5fd"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/math/div",component:f("/docs/0.16.0/sql-syntax/functions/math/div","ea6"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/math/exp",component:f("/docs/0.16.0/sql-syntax/functions/math/exp","a42"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/math/floor",component:f("/docs/0.16.0/sql-syntax/functions/math/floor","cef"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/math/gcd",component:f("/docs/0.16.0/sql-syntax/functions/math/gcd","95e"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/math/lcm",component:f("/docs/0.16.0/sql-syntax/functions/math/lcm","394"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/math/ln",component:f("/docs/0.16.0/sql-syntax/functions/math/ln","b8a"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/math/log",component:f("/docs/0.16.0/sql-syntax/functions/math/log","4b4"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/math/log10",component:f("/docs/0.16.0/sql-syntax/functions/math/log10","589"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/math/log2",component:f("/docs/0.16.0/sql-syntax/functions/math/log2","002"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/math/mod",component:f("/docs/0.16.0/sql-syntax/functions/math/mod","d1b"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/math/pi",component:f("/docs/0.16.0/sql-syntax/functions/math/pi","d03"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/math/power",component:f("/docs/0.16.0/sql-syntax/functions/math/power","e3b"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/math/radians",component:f("/docs/0.16.0/sql-syntax/functions/math/radians","f1b"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/math/rand",component:f("/docs/0.16.0/sql-syntax/functions/math/rand","fd2"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/math/round",component:f("/docs/0.16.0/sql-syntax/functions/math/round","9da"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/math/sign",component:f("/docs/0.16.0/sql-syntax/functions/math/sign","3f7"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/math/sin",component:f("/docs/0.16.0/sql-syntax/functions/math/sin","b9a"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/math/sqrt",component:f("/docs/0.16.0/sql-syntax/functions/math/sqrt","287"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/math/tan",component:f("/docs/0.16.0/sql-syntax/functions/math/tan","69c"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/others/cast",component:f("/docs/0.16.0/sql-syntax/functions/others/cast","387"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/others/generate-uuid",component:f("/docs/0.16.0/sql-syntax/functions/others/generate-uuid","e66"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/others/ifnull",component:f("/docs/0.16.0/sql-syntax/functions/others/ifnull","a75"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/text/ascii",component:f("/docs/0.16.0/sql-syntax/functions/text/ascii","cbf"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/text/chr",component:f("/docs/0.16.0/sql-syntax/functions/text/chr","570"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/text/concat",component:f("/docs/0.16.0/sql-syntax/functions/text/concat","95d"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/text/concat-ws",component:f("/docs/0.16.0/sql-syntax/functions/text/concat-ws","f26"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/text/find-idx",component:f("/docs/0.16.0/sql-syntax/functions/text/find-idx","736"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/text/initcap",component:f("/docs/0.16.0/sql-syntax/functions/text/initcap","0f6"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/text/left",component:f("/docs/0.16.0/sql-syntax/functions/text/left","9eb"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/text/lower",component:f("/docs/0.16.0/sql-syntax/functions/text/lower","e33"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/text/lpad",component:f("/docs/0.16.0/sql-syntax/functions/text/lpad","a51"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/text/ltrim",component:f("/docs/0.16.0/sql-syntax/functions/text/ltrim","8e7"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/text/position",component:f("/docs/0.16.0/sql-syntax/functions/text/position","ffa"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/text/repeat",component:f("/docs/0.16.0/sql-syntax/functions/text/repeat","44f"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/text/reverse",component:f("/docs/0.16.0/sql-syntax/functions/text/reverse","6ec"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/text/right",component:f("/docs/0.16.0/sql-syntax/functions/text/right","c35"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/text/rpad",component:f("/docs/0.16.0/sql-syntax/functions/text/rpad","dd5"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/text/rtrim",component:f("/docs/0.16.0/sql-syntax/functions/text/rtrim","ab5"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/text/substr",component:f("/docs/0.16.0/sql-syntax/functions/text/substr","389"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/text/trim",component:f("/docs/0.16.0/sql-syntax/functions/text/trim","f09"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/functions/text/upper",component:f("/docs/0.16.0/sql-syntax/functions/text/upper","9fe"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/intro",component:f("/docs/0.16.0/sql-syntax/intro","4ad"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/statements/data-definition/alter-table",component:f("/docs/0.16.0/sql-syntax/statements/data-definition/alter-table","426"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/statements/data-definition/create-index",component:f("/docs/0.16.0/sql-syntax/statements/data-definition/create-index","15a"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/statements/data-definition/create-table",component:f("/docs/0.16.0/sql-syntax/statements/data-definition/create-table","db9"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/statements/data-definition/drop-index",component:f("/docs/0.16.0/sql-syntax/statements/data-definition/drop-index","4b8"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/statements/data-definition/drop-table",component:f("/docs/0.16.0/sql-syntax/statements/data-definition/drop-table","d17"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/statements/data-manipulation/delete",component:f("/docs/0.16.0/sql-syntax/statements/data-manipulation/delete","446"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/statements/data-manipulation/insert",component:f("/docs/0.16.0/sql-syntax/statements/data-manipulation/insert","d9a"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/statements/data-manipulation/update",component:f("/docs/0.16.0/sql-syntax/statements/data-manipulation/update","67b"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/statements/metadata/data-dictionary",component:f("/docs/0.16.0/sql-syntax/statements/metadata/data-dictionary","2d3"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/statements/metadata/show-tables",component:f("/docs/0.16.0/sql-syntax/statements/metadata/show-tables","864"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/statements/querying/aggregation",component:f("/docs/0.16.0/sql-syntax/statements/querying/aggregation","dc5"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/statements/querying/join",component:f("/docs/0.16.0/sql-syntax/statements/querying/join","217"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/statements/querying/limit",component:f("/docs/0.16.0/sql-syntax/statements/querying/limit","437"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/statements/querying/schemaless",component:f("/docs/0.16.0/sql-syntax/statements/querying/schemaless","ee2"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/statements/querying/where",component:f("/docs/0.16.0/sql-syntax/statements/querying/where","9f4"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/sql-syntax/statements/transaction",component:f("/docs/0.16.0/sql-syntax/statements/transaction","f5c"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/storages/developing-custom-storages/intro",component:f("/docs/0.16.0/storages/developing-custom-storages/intro","6c1"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/storages/developing-custom-storages/store-traits/alter-table",component:f("/docs/0.16.0/storages/developing-custom-storages/store-traits/alter-table","aad"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/storages/developing-custom-storages/store-traits/custom-function",component:f("/docs/0.16.0/storages/developing-custom-storages/store-traits/custom-function","015"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/storages/developing-custom-storages/store-traits/custom-function-mut",component:f("/docs/0.16.0/storages/developing-custom-storages/store-traits/custom-function-mut","056"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/storages/developing-custom-storages/store-traits/index-mut",component:f("/docs/0.16.0/storages/developing-custom-storages/store-traits/index-mut","9d8"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/storages/developing-custom-storages/store-traits/index-trait",component:f("/docs/0.16.0/storages/developing-custom-storages/store-traits/index-trait","26c"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/storages/developing-custom-storages/store-traits/metadata",component:f("/docs/0.16.0/storages/developing-custom-storages/store-traits/metadata","1eb"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/storages/developing-custom-storages/store-traits/store",component:f("/docs/0.16.0/storages/developing-custom-storages/store-traits/store","0ad"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/storages/developing-custom-storages/store-traits/store-mut",component:f("/docs/0.16.0/storages/developing-custom-storages/store-traits/store-mut","862"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/storages/developing-custom-storages/store-traits/transaction",component:f("/docs/0.16.0/storages/developing-custom-storages/store-traits/transaction","12b"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/storages/developing-custom-storages/using-test-suite",component:f("/docs/0.16.0/storages/developing-custom-storages/using-test-suite","5ee"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/storages/intro",component:f("/docs/0.16.0/storages/intro","6dd"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/storages/supported-storages/composite-storage",component:f("/docs/0.16.0/storages/supported-storages/composite-storage","3ce"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/storages/supported-storages/csv-storage",component:f("/docs/0.16.0/storages/supported-storages/csv-storage","353"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/storages/supported-storages/idb-storage",component:f("/docs/0.16.0/storages/supported-storages/idb-storage","8c8"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/storages/supported-storages/json-storage",component:f("/docs/0.16.0/storages/supported-storages/json-storage","bb2"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/storages/supported-storages/memory-storage",component:f("/docs/0.16.0/storages/supported-storages/memory-storage","e63"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/storages/supported-storages/parquet-storage",component:f("/docs/0.16.0/storages/supported-storages/parquet-storage","d14"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/storages/supported-storages/shared-memory-storage",component:f("/docs/0.16.0/storages/supported-storages/shared-memory-storage","632"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/storages/supported-storages/sled-storage",component:f("/docs/0.16.0/storages/supported-storages/sled-storage","652"),exact:!0,sidebar:"autoSidebar"},{path:"/docs/0.16.0/storages/supported-storages/web-storage",component:f("/docs/0.16.0/storages/supported-storages/web-storage","7d2"),exact:!0,sidebar:"autoSidebar"}]},{path:"*",component:f("*")}]},6125:(e,t,n)=>{"use strict";n.d(t,{o:()=>r,x:()=>o});var a=n(6540);const r=a.createContext(!1);function o(e){let{children:t}=e;const[n,o]=(0,a.useState)(!1);return(0,a.useEffect)((()=>{o(!0)}),[]),a.createElement(r.Provider,{value:n},t)}},8536:(e,t,n)=>{"use strict";var a=n(6540),r=n(961),o=n(4625),s=n(545),i=n(8193);const l=[n(119),n(6134),n(6294),n(1043)];var c=n(8328),u=n(6347),d=n(2831);function f(e){let{children:t}=e;return a.createElement(a.Fragment,null,t)}var p=n(8168),m=n(5260),g=n(4586),h=n(6025),b=n(6342),y=n(1003),v=n(2131),x=n(4090),w=n(2967),S=n(440),E=n(1463);function k(){const{i18n:{defaultLocale:e,localeConfigs:t}}=(0,g.A)(),n=(0,v.o)();return a.createElement(m.A,null,Object.entries(t).map((e=>{let[t,{htmlLang:r}]=e;return a.createElement("link",{key:t,rel:"alternate",href:n.createUrl({locale:t,fullyQualified:!0}),hrefLang:r})})),a.createElement("link",{rel:"alternate",href:n.createUrl({locale:e,fullyQualified:!0}),hrefLang:"x-default"}))}function _(e){let{permalink:t}=e;const{siteConfig:{url:n}}=(0,g.A)(),r=function(){const{siteConfig:{url:e,baseUrl:t,trailingSlash:n}}=(0,g.A)(),{pathname:a}=(0,u.zy)();return e+(0,S.applyTrailingSlash)((0,h.A)(a),{trailingSlash:n,baseUrl:t})}(),o=t?`${n}${t}`:r;return a.createElement(m.A,null,a.createElement("meta",{property:"og:url",content:o}),a.createElement("link",{rel:"canonical",href:o}))}function A(){const{i18n:{currentLocale:e}}=(0,g.A)(),{metadata:t,image:n}=(0,b.p)();return a.createElement(a.Fragment,null,a.createElement(m.A,null,a.createElement("meta",{name:"twitter:card",content:"summary_large_image"}),a.createElement("body",{className:x.w})),n&&a.createElement(y.be,{image:n}),a.createElement(_,null),a.createElement(k,null),a.createElement(E.A,{tag:w.Cy,locale:e}),a.createElement(m.A,null,t.map(((e,t)=>a.createElement("meta",(0,p.A)({key:t},e))))))}const C=new Map;function q(e){if(C.has(e.pathname))return{...e,pathname:C.get(e.pathname)};if((0,d.u)(c.A,e.pathname).some((e=>{let{route:t}=e;return!0===t.exact})))return C.set(e.pathname,e.pathname),e;const t=e.pathname.trim().replace(/(?:\/index)?\.html$/,"")||"/";return C.set(e.pathname,t),{...e,pathname:t}}var T=n(6125),N=n(6988);function L(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),a=1;a<t;a++)n[a-1]=arguments[a];const r=l.map((t=>{const a=t.default?.[e]??t[e];return a?.(...n)}));return()=>r.forEach((e=>e?.()))}const O=function(e){let{children:t,location:n,previousLocation:r}=e;return(0,a.useLayoutEffect)((()=>{r!==n&&(!function(e){let{location:t,previousLocation:n}=e;if(!n)return;const a=t.pathname===n.pathname,r=t.hash===n.hash,o=t.search===n.search;if(a&&r&&!o)return;const{hash:s}=t;if(s){const e=decodeURIComponent(s.substring(1)),t=document.getElementById(e);t?.scrollIntoView()}else window.scrollTo(0,0)}({location:n,previousLocation:r}),L("onRouteDidUpdate",{previousLocation:r,location:n}))}),[r,n]),t};function P(e){const t=Array.from(new Set([e,decodeURI(e)])).map((e=>(0,d.u)(c.A,e))).flat();return Promise.all(t.map((e=>e.route.component.preload?.())))}class R extends a.Component{previousLocation;routeUpdateCleanupCb;constructor(e){super(e),this.previousLocation=null,this.routeUpdateCleanupCb=i.A.canUseDOM?L("onRouteUpdate",{previousLocation:null,location:this.props.location}):()=>{},this.state={nextRouteHasLoaded:!0}}shouldComponentUpdate(e,t){if(e.location===this.props.location)return t.nextRouteHasLoaded;const n=e.location;return this.previousLocation=this.props.location,this.setState({nextRouteHasLoaded:!1}),this.routeUpdateCleanupCb=L("onRouteUpdate",{previousLocation:this.previousLocation,location:n}),P(n.pathname).then((()=>{this.routeUpdateCleanupCb(),this.setState({nextRouteHasLoaded:!0})})).catch((e=>{console.warn(e),window.location.reload()})),!1}render(){const{children:e,location:t}=this.props;return a.createElement(O,{previousLocation:this.previousLocation,location:t},a.createElement(u.qh,{location:t,render:()=>e}))}}const I=R,M="__docusaurus-base-url-issue-banner-container",D="__docusaurus-base-url-issue-banner",F="__docusaurus-base-url-issue-banner-suggestion-container",B="__DOCUSAURUS_INSERT_BASEURL_BANNER";function j(e){return`\nwindow['${B}'] = true;\n\ndocument.addEventListener('DOMContentLoaded', maybeInsertBanner);\n\nfunction maybeInsertBanner() {\n var shouldInsert = window['${B}'];\n shouldInsert && insertBanner();\n}\n\nfunction insertBanner() {\n var bannerContainer = document.getElementById('${M}');\n if (!bannerContainer) {\n return;\n }\n var bannerHtml = ${JSON.stringify(function(e){return`\n<div id="${D}" style="border: thick solid red; background-color: rgb(255, 230, 179); margin: 20px; padding: 20px; font-size: 20px;">\n <p style="font-weight: bold; font-size: 30px;">Your Docusaurus site did not load properly.</p>\n <p>A very common reason is a wrong site <a href="https://docusaurus.io/docs/docusaurus.config.js/#baseUrl" style="font-weight: bold;">baseUrl configuration</a>.</p>\n <p>Current configured baseUrl = <span style="font-weight: bold; color: red;">${e}</span> ${"/"===e?" (default value)":""}</p>\n <p>We suggest trying baseUrl = <span id="${F}" style="font-weight: bold; color: green;"></span></p>\n</div>\n`}(e)).replace(/</g,"\\<")};\n bannerContainer.innerHTML = bannerHtml;\n var suggestionContainer = document.getElementById('${F}');\n var actualHomePagePath = window.location.pathname;\n var suggestedBaseUrl = actualHomePagePath.substr(-1) === '/'\n ? actualHomePagePath\n : actualHomePagePath + '/';\n suggestionContainer.innerHTML = suggestedBaseUrl;\n}\n`}function z(){const{siteConfig:{baseUrl:e}}=(0,g.A)();return(0,a.useLayoutEffect)((()=>{window[B]=!1}),[]),a.createElement(a.Fragment,null,!i.A.canUseDOM&&a.createElement(m.A,null,a.createElement("script",null,j(e))),a.createElement("div",{id:M}))}function $(){const{siteConfig:{baseUrl:e,baseUrlIssueBanner:t}}=(0,g.A)(),{pathname:n}=(0,u.zy)();return t&&n===e?a.createElement(z,null):null}function U(){const{siteConfig:{favicon:e,title:t,noIndex:n},i18n:{currentLocale:r,localeConfigs:o}}=(0,g.A)(),s=(0,h.A)(e),{htmlLang:i,direction:l}=o[r];return a.createElement(m.A,null,a.createElement("html",{lang:i,dir:l}),a.createElement("title",null,t),a.createElement("meta",{property:"og:title",content:t}),a.createElement("meta",{name:"viewport",content:"width=device-width, initial-scale=1.0"}),n&&a.createElement("meta",{name:"robots",content:"noindex, nofollow"}),e&&a.createElement("link",{rel:"icon",href:s}))}var H=n(7489),V=n(2303);function G(){const e=(0,V.A)();return a.createElement(m.A,null,a.createElement("html",{"data-has-hydrated":e}))}function W(){const e=(0,d.v)(c.A),t=(0,u.zy)();return a.createElement(H.A,null,a.createElement(N.l,null,a.createElement(T.x,null,a.createElement(f,null,a.createElement(U,null),a.createElement(A,null),a.createElement($,null),a.createElement(I,{location:q(t)},e)),a.createElement(G,null))))}var Y=n(4054);const K=function(e){try{return document.createElement("link").relList.supports(e)}catch{return!1}}("prefetch")?function(e){return new Promise(((t,n)=>{if("undefined"==typeof document)return void n();const a=document.createElement("link");a.setAttribute("rel","prefetch"),a.setAttribute("href",e),a.onload=()=>t(),a.onerror=()=>n();const r=document.getElementsByTagName("head")[0]??document.getElementsByName("script")[0]?.parentNode;r?.appendChild(a)}))}:function(e){return new Promise(((t,n)=>{const a=new XMLHttpRequest;a.open("GET",e,!0),a.withCredentials=!0,a.onload=()=>{200===a.status?t():n()},a.send(null)}))};var Q=n(6921);const X=new Set,Z=new Set,J=()=>navigator.connection?.effectiveType.includes("2g")||navigator.connection?.saveData,ee={prefetch(e){if(!(e=>!J()&&!Z.has(e)&&!X.has(e))(e))return!1;X.add(e);const t=(0,d.u)(c.A,e).flatMap((e=>{return t=e.route.path,Object.entries(Y).filter((e=>{let[n]=e;return n.replace(/-[^-]+$/,"")===t})).flatMap((e=>{let[,t]=e;return Object.values((0,Q.A)(t))}));var t}));return Promise.all(t.map((e=>{const t=n.gca(e);return t&&!t.includes("undefined")?K(t).catch((()=>{})):Promise.resolve()})))},preload:e=>!!(e=>!J()&&!Z.has(e))(e)&&(Z.add(e),P(e))},te=Object.freeze(ee);if(i.A.canUseDOM){window.docusaurus=te;const e=r.hydrate;P(window.location.pathname).then((()=>{e(a.createElement(s.vd,null,a.createElement(o.Kd,null,a.createElement(W,null))),document.getElementById("__docusaurus"))}))}},6988:(e,t,n)=>{"use strict";n.d(t,{o:()=>u,l:()=>d});var a=n(6540),r=n(4784);const o=JSON.parse('{"docusaurus-plugin-content-docs":{"default":{"path":"/docs/0.16.0/","versions":[{"name":"current","label":"Next","isLast":true,"path":"/docs/0.16.0/","mainDocId":"index","docs":[{"id":"ast-builder/expressions/conditional","path":"/docs/0.16.0/ast-builder/expressions/conditional","sidebar":"autoSidebar"},{"id":"ast-builder/expressions/nested","path":"/docs/0.16.0/ast-builder/expressions/nested","sidebar":"autoSidebar"},{"id":"ast-builder/expressions/operator-based","path":"/docs/0.16.0/ast-builder/expressions/operator-based","sidebar":"autoSidebar"},{"id":"ast-builder/expressions/pattern-matching","path":"/docs/0.16.0/ast-builder/expressions/pattern-matching","sidebar":"autoSidebar"},{"id":"ast-builder/expressions/value-checking","path":"/docs/0.16.0/ast-builder/expressions/value-checking","sidebar":"autoSidebar"},{"id":"ast-builder/functions/date-&-time/conversion","path":"/docs/0.16.0/ast-builder/functions/date-&-time/conversion","sidebar":"autoSidebar"},{"id":"ast-builder/functions/date-&-time/current-date-and-time","path":"/docs/0.16.0/ast-builder/functions/date-&-time/current-date-and-time","sidebar":"autoSidebar"},{"id":"ast-builder/functions/date-&-time/date-and-time-extraction","path":"/docs/0.16.0/ast-builder/functions/date-&-time/date-and-time-extraction","sidebar":"autoSidebar"},{"id":"ast-builder/functions/date-&-time/formatting","path":"/docs/0.16.0/ast-builder/functions/date-&-time/formatting","sidebar":"autoSidebar"},{"id":"ast-builder/functions/geometry/coordinate-extraction","path":"/docs/0.16.0/ast-builder/functions/geometry/coordinate-extraction","sidebar":"autoSidebar"},{"id":"ast-builder/functions/geometry/distance-calculation","path":"/docs/0.16.0/ast-builder/functions/geometry/distance-calculation","sidebar":"autoSidebar"},{"id":"ast-builder/functions/geometry/point-creation","path":"/docs/0.16.0/ast-builder/functions/geometry/point-creation","sidebar":"autoSidebar"},{"id":"ast-builder/functions/list-&-map/list-and-map-concatenation","path":"/docs/0.16.0/ast-builder/functions/list-&-map/list-and-map-concatenation","sidebar":"autoSidebar"},{"id":"ast-builder/functions/list-&-map/list-manipulation","path":"/docs/0.16.0/ast-builder/functions/list-&-map/list-manipulation","sidebar":"autoSidebar"},{"id":"ast-builder/functions/math/basic-arithmetic","path":"/docs/0.16.0/ast-builder/functions/math/basic-arithmetic","sidebar":"autoSidebar"},{"id":"ast-builder/functions/math/conversion","path":"/docs/0.16.0/ast-builder/functions/math/conversion","sidebar":"autoSidebar"},{"id":"ast-builder/functions/math/logarithmic-and-exponential","path":"/docs/0.16.0/ast-builder/functions/math/logarithmic-and-exponential","sidebar":"autoSidebar"},{"id":"ast-builder/functions/math/rounding","path":"/docs/0.16.0/ast-builder/functions/math/rounding","sidebar":"autoSidebar"},{"id":"ast-builder/functions/math/special-mathematical","path":"/docs/0.16.0/ast-builder/functions/math/special-mathematical","sidebar":"autoSidebar"},{"id":"ast-builder/functions/math/trigonometric","path":"/docs/0.16.0/ast-builder/functions/math/trigonometric","sidebar":"autoSidebar"},{"id":"ast-builder/functions/others/null-handling","path":"/docs/0.16.0/ast-builder/functions/others/null-handling","sidebar":"autoSidebar"},{"id":"ast-builder/functions/others/type-conversion","path":"/docs/0.16.0/ast-builder/functions/others/type-conversion","sidebar":"autoSidebar"},{"id":"ast-builder/functions/others/unique-identifier","path":"/docs/0.16.0/ast-builder/functions/others/unique-identifier","sidebar":"autoSidebar"},{"id":"ast-builder/functions/text/case-conversion","path":"/docs/0.16.0/ast-builder/functions/text/case-conversion","sidebar":"autoSidebar"},{"id":"ast-builder/functions/text/character-conversion","path":"/docs/0.16.0/ast-builder/functions/text/character-conversion","sidebar":"autoSidebar"},{"id":"ast-builder/functions/text/padding","path":"/docs/0.16.0/ast-builder/functions/text/padding","sidebar":"autoSidebar"},{"id":"ast-builder/functions/text/position-and-indexing","path":"/docs/0.16.0/ast-builder/functions/text/position-and-indexing","sidebar":"autoSidebar"},{"id":"ast-builder/functions/text/text-manipulation","path":"/docs/0.16.0/ast-builder/functions/text/text-manipulation","sidebar":"autoSidebar"},{"id":"ast-builder/functions/text/trimming","path":"/docs/0.16.0/ast-builder/functions/text/trimming","sidebar":"autoSidebar"},{"id":"ast-builder/intro","path":"/docs/0.16.0/ast-builder/intro","sidebar":"autoSidebar"},{"id":"ast-builder/statements/data-manipulation/deleting-data","path":"/docs/0.16.0/ast-builder/statements/data-manipulation/deleting-data","sidebar":"autoSidebar"},{"id":"ast-builder/statements/data-manipulation/inserting-data","path":"/docs/0.16.0/ast-builder/statements/data-manipulation/inserting-data","sidebar":"autoSidebar"},{"id":"ast-builder/statements/data-manipulation/updating-data","path":"/docs/0.16.0/ast-builder/statements/data-manipulation/updating-data","sidebar":"autoSidebar"},{"id":"ast-builder/statements/querying/creating-derived-subqueries","path":"/docs/0.16.0/ast-builder/statements/querying/creating-derived-subqueries","sidebar":"autoSidebar"},{"id":"ast-builder/statements/querying/data-aggregation","path":"/docs/0.16.0/ast-builder/statements/querying/data-aggregation","sidebar":"autoSidebar"},{"id":"ast-builder/statements/querying/data-injection","path":"/docs/0.16.0/ast-builder/statements/querying/data-injection","sidebar":"autoSidebar"},{"id":"ast-builder/statements/querying/data-joining","path":"/docs/0.16.0/ast-builder/statements/querying/data-joining","sidebar":"autoSidebar"},{"id":"ast-builder/statements/querying/data-selection-and-projection","path":"/docs/0.16.0/ast-builder/statements/querying/data-selection-and-projection","sidebar":"autoSidebar"},{"id":"ast-builder/statements/querying/data-sorting-and-limiting","path":"/docs/0.16.0/ast-builder/statements/querying/data-sorting-and-limiting","sidebar":"autoSidebar"},{"id":"ast-builder/statements/querying/fetching-data-from-storage","path":"/docs/0.16.0/ast-builder/statements/querying/fetching-data-from-storage","sidebar":"autoSidebar"},{"id":"ast-builder/statements/querying/using-preloaded-data","path":"/docs/0.16.0/ast-builder/statements/querying/using-preloaded-data","sidebar":"autoSidebar"},{"id":"getting-started/cli","path":"/docs/0.16.0/getting-started/cli","sidebar":"autoSidebar"},{"id":"getting-started/javascript-web","path":"/docs/0.16.0/getting-started/javascript-web","sidebar":"autoSidebar"},{"id":"getting-started/nodejs","path":"/docs/0.16.0/getting-started/nodejs","sidebar":"autoSidebar"},{"id":"getting-started/rust","path":"/docs/0.16.0/getting-started/rust","sidebar":"autoSidebar"},{"id":"index","path":"/docs/0.16.0/","sidebar":"autoSidebar"},{"id":"sql-syntax/data-types/boolean","path":"/docs/0.16.0/sql-syntax/data-types/boolean","sidebar":"autoSidebar"},{"id":"sql-syntax/data-types/bytea","path":"/docs/0.16.0/sql-syntax/data-types/bytea","sidebar":"autoSidebar"},{"id":"sql-syntax/data-types/date","path":"/docs/0.16.0/sql-syntax/data-types/date","sidebar":"autoSidebar"},{"id":"sql-syntax/data-types/decimal","path":"/docs/0.16.0/sql-syntax/data-types/decimal","sidebar":"autoSidebar"},{"id":"sql-syntax/data-types/float","path":"/docs/0.16.0/sql-syntax/data-types/float","sidebar":"autoSidebar"},{"id":"sql-syntax/data-types/inet","path":"/docs/0.16.0/sql-syntax/data-types/inet","sidebar":"autoSidebar"},{"id":"sql-syntax/data-types/integers","path":"/docs/0.16.0/sql-syntax/data-types/integers","sidebar":"autoSidebar"},{"id":"sql-syntax/data-types/interval","path":"/docs/0.16.0/sql-syntax/data-types/interval","sidebar":"autoSidebar"},{"id":"sql-syntax/data-types/list","path":"/docs/0.16.0/sql-syntax/data-types/list","sidebar":"autoSidebar"},{"id":"sql-syntax/data-types/map","path":"/docs/0.16.0/sql-syntax/data-types/map","sidebar":"autoSidebar"},{"id":"sql-syntax/data-types/text","path":"/docs/0.16.0/sql-syntax/data-types/text","sidebar":"autoSidebar"},{"id":"sql-syntax/data-types/time","path":"/docs/0.16.0/sql-syntax/data-types/time","sidebar":"autoSidebar"},{"id":"sql-syntax/data-types/timestamp","path":"/docs/0.16.0/sql-syntax/data-types/timestamp","sidebar":"autoSidebar"},{"id":"sql-syntax/data-types/uuid","path":"/docs/0.16.0/sql-syntax/data-types/uuid","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/datetime/extract","path":"/docs/0.16.0/sql-syntax/functions/datetime/extract","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/datetime/format","path":"/docs/0.16.0/sql-syntax/functions/datetime/format","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/datetime/now","path":"/docs/0.16.0/sql-syntax/functions/datetime/now","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/datetime/to-date","path":"/docs/0.16.0/sql-syntax/functions/datetime/to-date","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/datetime/to-time","path":"/docs/0.16.0/sql-syntax/functions/datetime/to-time","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/datetime/to-timestamp","path":"/docs/0.16.0/sql-syntax/functions/datetime/to-timestamp","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/geometry/calc-distance","path":"/docs/0.16.0/sql-syntax/functions/geometry/calc-distance","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/geometry/get-x","path":"/docs/0.16.0/sql-syntax/functions/geometry/get-x","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/geometry/get-y","path":"/docs/0.16.0/sql-syntax/functions/geometry/get-y","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/geometry/point","path":"/docs/0.16.0/sql-syntax/functions/geometry/point","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/list-map/append","path":"/docs/0.16.0/sql-syntax/functions/list-map/append","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/list-map/concat","path":"/docs/0.16.0/sql-syntax/functions/list-map/concat","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/list-map/prepend","path":"/docs/0.16.0/sql-syntax/functions/list-map/prepend","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/list-map/slice","path":"/docs/0.16.0/sql-syntax/functions/list-map/slice","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/list-map/splice","path":"/docs/0.16.0/sql-syntax/functions/list-map/splice","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/math/abs","path":"/docs/0.16.0/sql-syntax/functions/math/abs","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/math/acos","path":"/docs/0.16.0/sql-syntax/functions/math/acos","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/math/asin","path":"/docs/0.16.0/sql-syntax/functions/math/asin","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/math/atan","path":"/docs/0.16.0/sql-syntax/functions/math/atan","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/math/ceil","path":"/docs/0.16.0/sql-syntax/functions/math/ceil","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/math/cos","path":"/docs/0.16.0/sql-syntax/functions/math/cos","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/math/degrees","path":"/docs/0.16.0/sql-syntax/functions/math/degrees","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/math/div","path":"/docs/0.16.0/sql-syntax/functions/math/div","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/math/exp","path":"/docs/0.16.0/sql-syntax/functions/math/exp","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/math/floor","path":"/docs/0.16.0/sql-syntax/functions/math/floor","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/math/gcd","path":"/docs/0.16.0/sql-syntax/functions/math/gcd","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/math/lcm","path":"/docs/0.16.0/sql-syntax/functions/math/lcm","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/math/ln","path":"/docs/0.16.0/sql-syntax/functions/math/ln","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/math/log","path":"/docs/0.16.0/sql-syntax/functions/math/log","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/math/log10","path":"/docs/0.16.0/sql-syntax/functions/math/log10","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/math/log2","path":"/docs/0.16.0/sql-syntax/functions/math/log2","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/math/mod","path":"/docs/0.16.0/sql-syntax/functions/math/mod","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/math/pi","path":"/docs/0.16.0/sql-syntax/functions/math/pi","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/math/power","path":"/docs/0.16.0/sql-syntax/functions/math/power","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/math/radians","path":"/docs/0.16.0/sql-syntax/functions/math/radians","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/math/rand","path":"/docs/0.16.0/sql-syntax/functions/math/rand","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/math/round","path":"/docs/0.16.0/sql-syntax/functions/math/round","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/math/sign","path":"/docs/0.16.0/sql-syntax/functions/math/sign","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/math/sin","path":"/docs/0.16.0/sql-syntax/functions/math/sin","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/math/sqrt","path":"/docs/0.16.0/sql-syntax/functions/math/sqrt","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/math/tan","path":"/docs/0.16.0/sql-syntax/functions/math/tan","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/others/cast","path":"/docs/0.16.0/sql-syntax/functions/others/cast","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/others/generate-uuid","path":"/docs/0.16.0/sql-syntax/functions/others/generate-uuid","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/others/ifnull","path":"/docs/0.16.0/sql-syntax/functions/others/ifnull","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/text/ascii","path":"/docs/0.16.0/sql-syntax/functions/text/ascii","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/text/chr","path":"/docs/0.16.0/sql-syntax/functions/text/chr","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/text/concat","path":"/docs/0.16.0/sql-syntax/functions/text/concat","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/text/concat-ws","path":"/docs/0.16.0/sql-syntax/functions/text/concat-ws","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/text/find-idx","path":"/docs/0.16.0/sql-syntax/functions/text/find-idx","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/text/initcap","path":"/docs/0.16.0/sql-syntax/functions/text/initcap","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/text/left","path":"/docs/0.16.0/sql-syntax/functions/text/left","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/text/lower","path":"/docs/0.16.0/sql-syntax/functions/text/lower","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/text/lpad","path":"/docs/0.16.0/sql-syntax/functions/text/lpad","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/text/ltrim","path":"/docs/0.16.0/sql-syntax/functions/text/ltrim","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/text/position","path":"/docs/0.16.0/sql-syntax/functions/text/position","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/text/repeat","path":"/docs/0.16.0/sql-syntax/functions/text/repeat","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/text/reverse","path":"/docs/0.16.0/sql-syntax/functions/text/reverse","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/text/right","path":"/docs/0.16.0/sql-syntax/functions/text/right","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/text/rpad","path":"/docs/0.16.0/sql-syntax/functions/text/rpad","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/text/rtrim","path":"/docs/0.16.0/sql-syntax/functions/text/rtrim","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/text/substr","path":"/docs/0.16.0/sql-syntax/functions/text/substr","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/text/trim","path":"/docs/0.16.0/sql-syntax/functions/text/trim","sidebar":"autoSidebar"},{"id":"sql-syntax/functions/text/upper","path":"/docs/0.16.0/sql-syntax/functions/text/upper","sidebar":"autoSidebar"},{"id":"sql-syntax/intro","path":"/docs/0.16.0/sql-syntax/intro","sidebar":"autoSidebar"},{"id":"sql-syntax/statements/data-definition/alter-table","path":"/docs/0.16.0/sql-syntax/statements/data-definition/alter-table","sidebar":"autoSidebar"},{"id":"sql-syntax/statements/data-definition/create-index","path":"/docs/0.16.0/sql-syntax/statements/data-definition/create-index","sidebar":"autoSidebar"},{"id":"sql-syntax/statements/data-definition/create-table","path":"/docs/0.16.0/sql-syntax/statements/data-definition/create-table","sidebar":"autoSidebar"},{"id":"sql-syntax/statements/data-definition/drop-index","path":"/docs/0.16.0/sql-syntax/statements/data-definition/drop-index","sidebar":"autoSidebar"},{"id":"sql-syntax/statements/data-definition/drop-table","path":"/docs/0.16.0/sql-syntax/statements/data-definition/drop-table","sidebar":"autoSidebar"},{"id":"sql-syntax/statements/data-manipulation/delete","path":"/docs/0.16.0/sql-syntax/statements/data-manipulation/delete","sidebar":"autoSidebar"},{"id":"sql-syntax/statements/data-manipulation/insert","path":"/docs/0.16.0/sql-syntax/statements/data-manipulation/insert","sidebar":"autoSidebar"},{"id":"sql-syntax/statements/data-manipulation/update","path":"/docs/0.16.0/sql-syntax/statements/data-manipulation/update","sidebar":"autoSidebar"},{"id":"sql-syntax/statements/metadata/data-dictionary","path":"/docs/0.16.0/sql-syntax/statements/metadata/data-dictionary","sidebar":"autoSidebar"},{"id":"sql-syntax/statements/metadata/show-tables","path":"/docs/0.16.0/sql-syntax/statements/metadata/show-tables","sidebar":"autoSidebar"},{"id":"sql-syntax/statements/querying/aggregation","path":"/docs/0.16.0/sql-syntax/statements/querying/aggregation","sidebar":"autoSidebar"},{"id":"sql-syntax/statements/querying/join","path":"/docs/0.16.0/sql-syntax/statements/querying/join","sidebar":"autoSidebar"},{"id":"sql-syntax/statements/querying/limit","path":"/docs/0.16.0/sql-syntax/statements/querying/limit","sidebar":"autoSidebar"},{"id":"sql-syntax/statements/querying/schemaless","path":"/docs/0.16.0/sql-syntax/statements/querying/schemaless","sidebar":"autoSidebar"},{"id":"sql-syntax/statements/querying/where","path":"/docs/0.16.0/sql-syntax/statements/querying/where","sidebar":"autoSidebar"},{"id":"sql-syntax/statements/transaction","path":"/docs/0.16.0/sql-syntax/statements/transaction","sidebar":"autoSidebar"},{"id":"storages/developing-custom-storages/intro","path":"/docs/0.16.0/storages/developing-custom-storages/intro","sidebar":"autoSidebar"},{"id":"storages/developing-custom-storages/store-traits/alter-table","path":"/docs/0.16.0/storages/developing-custom-storages/store-traits/alter-table","sidebar":"autoSidebar"},{"id":"storages/developing-custom-storages/store-traits/custom-function","path":"/docs/0.16.0/storages/developing-custom-storages/store-traits/custom-function","sidebar":"autoSidebar"},{"id":"storages/developing-custom-storages/store-traits/custom-function-mut","path":"/docs/0.16.0/storages/developing-custom-storages/store-traits/custom-function-mut","sidebar":"autoSidebar"},{"id":"storages/developing-custom-storages/store-traits/index-mut","path":"/docs/0.16.0/storages/developing-custom-storages/store-traits/index-mut","sidebar":"autoSidebar"},{"id":"storages/developing-custom-storages/store-traits/index-trait","path":"/docs/0.16.0/storages/developing-custom-storages/store-traits/index-trait","sidebar":"autoSidebar"},{"id":"storages/developing-custom-storages/store-traits/metadata","path":"/docs/0.16.0/storages/developing-custom-storages/store-traits/metadata","sidebar":"autoSidebar"},{"id":"storages/developing-custom-storages/store-traits/store","path":"/docs/0.16.0/storages/developing-custom-storages/store-traits/store","sidebar":"autoSidebar"},{"id":"storages/developing-custom-storages/store-traits/store-mut","path":"/docs/0.16.0/storages/developing-custom-storages/store-traits/store-mut","sidebar":"autoSidebar"},{"id":"storages/developing-custom-storages/store-traits/transaction","path":"/docs/0.16.0/storages/developing-custom-storages/store-traits/transaction","sidebar":"autoSidebar"},{"id":"storages/developing-custom-storages/using-test-suite","path":"/docs/0.16.0/storages/developing-custom-storages/using-test-suite","sidebar":"autoSidebar"},{"id":"storages/intro","path":"/docs/0.16.0/storages/intro","sidebar":"autoSidebar"},{"id":"storages/supported-storages/composite-storage","path":"/docs/0.16.0/storages/supported-storages/composite-storage","sidebar":"autoSidebar"},{"id":"storages/supported-storages/csv-storage","path":"/docs/0.16.0/storages/supported-storages/csv-storage","sidebar":"autoSidebar"},{"id":"storages/supported-storages/idb-storage","path":"/docs/0.16.0/storages/supported-storages/idb-storage","sidebar":"autoSidebar"},{"id":"storages/supported-storages/json-storage","path":"/docs/0.16.0/storages/supported-storages/json-storage","sidebar":"autoSidebar"},{"id":"storages/supported-storages/memory-storage","path":"/docs/0.16.0/storages/supported-storages/memory-storage","sidebar":"autoSidebar"},{"id":"storages/supported-storages/parquet-storage","path":"/docs/0.16.0/storages/supported-storages/parquet-storage","sidebar":"autoSidebar"},{"id":"storages/supported-storages/shared-memory-storage","path":"/docs/0.16.0/storages/supported-storages/shared-memory-storage","sidebar":"autoSidebar"},{"id":"storages/supported-storages/sled-storage","path":"/docs/0.16.0/storages/supported-storages/sled-storage","sidebar":"autoSidebar"},{"id":"storages/supported-storages/web-storage","path":"/docs/0.16.0/storages/supported-storages/web-storage","sidebar":"autoSidebar"}],"draftIds":[],"sidebars":{"autoSidebar":{"link":{"path":"/docs/0.16.0/","label":"index"}}}}],"breadcrumbs":true}}}'),s=JSON.parse('{"defaultLocale":"en","locales":["en"],"path":"i18n","currentLocale":"en","localeConfigs":{"en":{"label":"English","direction":"ltr","htmlLang":"en","calendar":"gregory","path":"en"}}}');var i=n(2654);const l=JSON.parse('{"docusaurusVersion":"2.4.3","siteVersion":"0.0.0","pluginVersions":{"docusaurus-plugin-content-docs":{"type":"package","name":"@docusaurus/plugin-content-docs","version":"2.4.3"},"docusaurus-plugin-content-blog":{"type":"package","name":"@docusaurus/plugin-content-blog","version":"2.4.3"},"docusaurus-plugin-sitemap":{"type":"package","name":"@docusaurus/plugin-sitemap","version":"2.4.3"},"docusaurus-theme-classic":{"type":"package","name":"@docusaurus/theme-classic","version":"2.4.3"}}}'),c={siteConfig:r.A,siteMetadata:l,globalData:o,i18n:s,codeTranslations:i},u=a.createContext(c);function d(e){let{children:t}=e;return a.createElement(u.Provider,{value:c},t)}},7489:(e,t,n)=>{"use strict";n.d(t,{A:()=>f});var a=n(6540),r=n(8193),o=n(5260),s=n(440),i=n(9408);function l(e){let{error:t,tryAgain:n}=e;return a.createElement("div",{style:{display:"flex",flexDirection:"column",justifyContent:"center",alignItems:"flex-start",minHeight:"100vh",width:"100%",maxWidth:"80ch",fontSize:"20px",margin:"0 auto",padding:"1rem"}},a.createElement("h1",{style:{fontSize:"3rem"}},"This page crashed"),a.createElement("button",{type:"button",onClick:n,style:{margin:"1rem 0",fontSize:"2rem",cursor:"pointer",borderRadius:20,padding:"1rem"}},"Try again"),a.createElement(c,{error:t}))}function c(e){let{error:t}=e;const n=(0,s.getErrorCausalChain)(t).map((e=>e.message)).join("\n\nCause:\n");return a.createElement("p",{style:{whiteSpace:"pre-wrap"}},n)}function u(e){let{error:t,tryAgain:n}=e;return a.createElement(f,{fallback:()=>a.createElement(l,{error:t,tryAgain:n})},a.createElement(o.A,null,a.createElement("title",null,"Page Error")),a.createElement(i.A,null,a.createElement(l,{error:t,tryAgain:n})))}const d=e=>a.createElement(u,e);class f extends a.Component{constructor(e){super(e),this.state={error:null}}componentDidCatch(e){r.A.canUseDOM&&this.setState({error:e})}render(){const{children:e}=this.props,{error:t}=this.state;if(t){const e={error:t,tryAgain:()=>this.setState({error:null})};return(this.props.fallback??d)(e)}return e??null}}},8193:(e,t,n)=>{"use strict";n.d(t,{A:()=>r});const a="undefined"!=typeof window&&"document"in window&&"createElement"in window.document,r={canUseDOM:a,canUseEventListeners:a&&("addEventListener"in window||"attachEvent"in window),canUseIntersectionObserver:a&&"IntersectionObserver"in window,canUseViewport:a&&"screen"in window}},5260:(e,t,n)=>{"use strict";n.d(t,{A:()=>o});var a=n(6540),r=n(545);function o(e){return a.createElement(r.mg,e)}},5489:(e,t,n)=>{"use strict";n.d(t,{A:()=>p});var a=n(8168),r=n(6540),o=n(4625),s=n(440),i=n(4586),l=n(6654),c=n(8193);const u=r.createContext({collectLink:()=>{}});var d=n(6025);function f(e,t){let{isNavLink:n,to:f,href:p,activeClassName:m,isActive:g,"data-noBrokenLinkCheck":h,autoAddBaseUrl:b=!0,...y}=e;const{siteConfig:{trailingSlash:v,baseUrl:x}}=(0,i.A)(),{withBaseUrl:w}=(0,d.h)(),S=(0,r.useContext)(u),E=(0,r.useRef)(null);(0,r.useImperativeHandle)(t,(()=>E.current));const k=f||p;const _=(0,l.A)(k),A=k?.replace("pathname://","");let C=void 0!==A?(q=A,b&&(e=>e.startsWith("/"))(q)?w(q):q):void 0;var q;C&&_&&(C=(0,s.applyTrailingSlash)(C,{trailingSlash:v,baseUrl:x}));const T=(0,r.useRef)(!1),N=n?o.k2:o.N_,L=c.A.canUseIntersectionObserver,O=(0,r.useRef)(),P=()=>{T.current||null==C||(window.docusaurus.preload(C),T.current=!0)};(0,r.useEffect)((()=>(!L&&_&&null!=C&&window.docusaurus.prefetch(C),()=>{L&&O.current&&O.current.disconnect()})),[O,C,L,_]);const R=C?.startsWith("#")??!1,I=!C||!_||R;return I||h||S.collectLink(C),I?r.createElement("a",(0,a.A)({ref:E,href:C},k&&!_&&{target:"_blank",rel:"noopener noreferrer"},y)):r.createElement(N,(0,a.A)({},y,{onMouseEnter:P,onTouchStart:P,innerRef:e=>{E.current=e,L&&e&&_&&(O.current=new window.IntersectionObserver((t=>{t.forEach((t=>{e===t.target&&(t.isIntersecting||t.intersectionRatio>0)&&(O.current.unobserve(e),O.current.disconnect(),null!=C&&window.docusaurus.prefetch(C))}))})),O.current.observe(e))},to:C},n&&{isActive:g,activeClassName:m}))}const p=r.forwardRef(f)},418:(e,t,n)=>{"use strict";n.d(t,{A:()=>a});const a=()=>null},1312:(e,t,n)=>{"use strict";n.d(t,{A:()=>l,T:()=>i});var a=n(6540);function r(e,t){const n=e.split(/(\{\w+\})/).map(((e,n)=>{if(n%2==1){const n=t?.[e.slice(1,-1)];if(void 0!==n)return n}return e}));return n.some((e=>(0,a.isValidElement)(e)))?n.map(((e,t)=>(0,a.isValidElement)(e)?a.cloneElement(e,{key:t}):e)).filter((e=>""!==e)):n.join("")}var o=n(2654);function s(e){let{id:t,message:n}=e;if(void 0===t&&void 0===n)throw new Error("Docusaurus translation declarations must have at least a translation id or a default translation message");return o[t??n]??n??t}function i(e,t){let{message:n,id:a}=e;return r(s({message:n,id:a}),t)}function l(e){let{children:t,id:n,values:o}=e;if(t&&"string"!=typeof t)throw console.warn("Illegal <Translate> children",t),new Error("The Docusaurus <Translate> component only accept simple string values");const i=s({message:t,id:n});return a.createElement(a.Fragment,null,r(i,o))}},7065:(e,t,n)=>{"use strict";n.d(t,{W:()=>a});const a="default"},6654:(e,t,n)=>{"use strict";function a(e){return/^(?:\w*:|\/\/)/.test(e)}function r(e){return void 0!==e&&!a(e)}n.d(t,{A:()=>r,z:()=>a})},6025:(e,t,n)=>{"use strict";n.d(t,{A:()=>i,h:()=>s});var a=n(6540),r=n(4586),o=n(6654);function s(){const{siteConfig:{baseUrl:e,url:t}}=(0,r.A)(),n=(0,a.useCallback)(((n,a)=>function(e,t,n,a){let{forcePrependBaseUrl:r=!1,absolute:s=!1}=void 0===a?{}:a;if(!n||n.startsWith("#")||(0,o.z)(n))return n;if(r)return t+n.replace(/^\//,"");if(n===t.replace(/\/$/,""))return t;const i=n.startsWith(t)?n:t+n.replace(/^\//,"");return s?e+i:i}(t,e,n,a)),[t,e]);return{withBaseUrl:n}}function i(e,t){void 0===t&&(t={});const{withBaseUrl:n}=s();return n(e,t)}},4586:(e,t,n)=>{"use strict";n.d(t,{A:()=>o});var a=n(6540),r=n(6988);function o(){return(0,a.useContext)(r.o)}},2303:(e,t,n)=>{"use strict";n.d(t,{A:()=>o});var a=n(6540),r=n(6125);function o(){return(0,a.useContext)(r.o)}},6921:(e,t,n)=>{"use strict";n.d(t,{A:()=>r});const a=e=>"object"==typeof e&&!!e&&Object.keys(e).length>0;function r(e){const t={};return function e(n,r){Object.entries(n).forEach((n=>{let[o,s]=n;const i=r?`${r}.${o}`:o;a(s)?e(s,i):t[i]=s}))}(e),t}},3102:(e,t,n)=>{"use strict";n.d(t,{W:()=>o,o:()=>r});var a=n(6540);const r=a.createContext(null);function o(e){let{children:t,value:n}=e;const o=a.useContext(r),s=(0,a.useMemo)((()=>function(e){let{parent:t,value:n}=e;if(!t){if(!n)throw new Error("Unexpected: no Docusaurus route context found");if(!("plugin"in n))throw new Error("Unexpected: Docusaurus topmost route context has no `plugin` attribute");return n}const a={...t.data,...n?.data};return{plugin:t.plugin,data:a}}({parent:o,value:n})),[o,n]);return a.createElement(r.Provider,{value:s},t)}},4070:(e,t,n)=>{"use strict";n.d(t,{zK:()=>g,vT:()=>f,Gy:()=>u,HW:()=>h,ht:()=>d,r7:()=>m,jh:()=>p});var a=n(6347),r=n(4586),o=n(7065);function s(e,t){void 0===t&&(t={});const n=function(){const{globalData:e}=(0,r.A)();return e}()[e];if(!n&&t.failfast)throw new Error(`Docusaurus plugin global data not found for "${e}" plugin.`);return n}const i=e=>e.versions.find((e=>e.isLast));function l(e,t){const n=function(e,t){const n=i(e);return[...e.versions.filter((e=>e!==n)),n].find((e=>!!(0,a.B6)(t,{path:e.path,exact:!1,strict:!1})))}(e,t),r=n?.docs.find((e=>!!(0,a.B6)(t,{path:e.path,exact:!0,strict:!1})));return{activeVersion:n,activeDoc:r,alternateDocVersions:r?function(t){const n={};return e.versions.forEach((e=>{e.docs.forEach((a=>{a.id===t&&(n[e.name]=a)}))})),n}(r.id):{}}}const c={},u=()=>s("docusaurus-plugin-content-docs")??c,d=e=>function(e,t,n){void 0===t&&(t=o.W),void 0===n&&(n={});const a=s(e),r=a?.[t];if(!r&&n.failfast)throw new Error(`Docusaurus plugin global data not found for "${e}" plugin with id "${t}".`);return r}("docusaurus-plugin-content-docs",e,{failfast:!0});function f(e){void 0===e&&(e={});const t=u(),{pathname:n}=(0,a.zy)();return function(e,t,n){void 0===n&&(n={});const r=Object.entries(e).sort(((e,t)=>t[1].path.localeCompare(e[1].path))).find((e=>{let[,n]=e;return!!(0,a.B6)(t,{path:n.path,exact:!1,strict:!1})})),o=r?{pluginId:r[0],pluginData:r[1]}:void 0;if(!o&&n.failfast)throw new Error(`Can't find active docs plugin for "${t}" pathname, while it was expected to be found. Maybe you tried to use a docs feature that can only be used on a docs-related page? Existing docs plugin paths are: ${Object.values(e).map((e=>e.path)).join(", ")}`);return o}(t,n,e)}function p(e){return d(e).versions}function m(e){const t=d(e);return i(t)}function g(e){const t=d(e),{pathname:n}=(0,a.zy)();return l(t,n)}function h(e){const t=d(e),{pathname:n}=(0,a.zy)();return function(e,t){const n=i(e);return{latestDocSuggestion:l(e,t).alternateDocVersions[n.name],latestVersionSuggestion:n}}(t,n)}},6294:(e,t,n)=>{"use strict";n.r(t),n.d(t,{default:()=>o});var a=n(5947),r=n.n(a);r().configure({showSpinner:!1});const o={onRouteUpdate(e){let{location:t,previousLocation:n}=e;if(n&&t.pathname!==n.pathname){const e=window.setTimeout((()=>{r().start()}),200);return()=>window.clearTimeout(e)}},onRouteDidUpdate(){r().done()}}},6134:(e,t,n)=>{"use strict";var a=n(1258),r=n(4784);!function(e){const{themeConfig:{prism:t}}=r.A,{additionalLanguages:a}=t;globalThis.Prism=e,a.forEach((e=>{n(3319)(`./prism-${e}`)})),delete globalThis.Prism}(a.A)},3186:(e,t,n)=>{"use strict";n.d(t,{A:()=>o});var a=n(6540);const r={iconExternalLink:"iconExternalLink_nPIU"};function o(e){let{width:t=13.5,height:n=13.5}=e;return a.createElement("svg",{width:t,height:n,"aria-hidden":"true",viewBox:"0 0 24 24",className:r.iconExternalLink},a.createElement("path",{fill:"currentColor",d:"M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"}))}},9408:(e,t,n)=>{"use strict";n.d(t,{A:()=>dt});var a=n(6540),r=n(53),o=n(7489),s=n(1003),i=n(8168),l=n(6347),c=n(1312),u=n(5062);const d="__docusaurus_skipToContent_fallback";function f(e){e.setAttribute("tabindex","-1"),e.focus(),e.removeAttribute("tabindex")}function p(){const e=(0,a.useRef)(null),{action:t}=(0,l.W6)(),n=(0,a.useCallback)((e=>{e.preventDefault();const t=document.querySelector("main:first-of-type")??document.getElementById(d);t&&f(t)}),[]);return(0,u.$)((n=>{let{location:a}=n;e.current&&!a.hash&&"PUSH"===t&&f(e.current)})),{containerRef:e,onClick:n}}const m=(0,c.T)({id:"theme.common.skipToMainContent",description:"The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation",message:"Skip to main content"});function g(e){const t=e.children??m,{containerRef:n,onClick:r}=p();return a.createElement("div",{ref:n,role:"region","aria-label":m},a.createElement("a",(0,i.A)({},e,{href:`#${d}`,onClick:r}),t))}var h=n(7559),b=n(4090);const y={skipToContent:"skipToContent_fXgn"};function v(){return a.createElement(g,{className:y.skipToContent})}var x=n(6342),w=n(5041);function S(e){let{width:t=21,height:n=21,color:r="currentColor",strokeWidth:o=1.2,className:s,...l}=e;return a.createElement("svg",(0,i.A)({viewBox:"0 0 15 15",width:t,height:n},l),a.createElement("g",{stroke:r,strokeWidth:o},a.createElement("path",{d:"M.75.75l13.5 13.5M14.25.75L.75 14.25"})))}const E={closeButton:"closeButton_CVFx"};function k(e){return a.createElement("button",(0,i.A)({type:"button","aria-label":(0,c.T)({id:"theme.AnnouncementBar.closeButtonAriaLabel",message:"Close",description:"The ARIA label for close button of announcement bar"})},e,{className:(0,r.A)("clean-btn close",E.closeButton,e.className)}),a.createElement(S,{width:14,height:14,strokeWidth:3.1}))}const _={content:"content_knG7"};function A(e){const{announcementBar:t}=(0,x.p)(),{content:n}=t;return a.createElement("div",(0,i.A)({},e,{className:(0,r.A)(_.content,e.className),dangerouslySetInnerHTML:{__html:n}}))}const C={announcementBar:"announcementBar_mb4j",announcementBarPlaceholder:"announcementBarPlaceholder_vyr4",announcementBarClose:"announcementBarClose_gvF7",announcementBarContent:"announcementBarContent_xLdY"};function q(){const{announcementBar:e}=(0,x.p)(),{isActive:t,close:n}=(0,w.Mj)();if(!t)return null;const{backgroundColor:r,textColor:o,isCloseable:s}=e;return a.createElement("div",{className:C.announcementBar,style:{backgroundColor:r,color:o},role:"banner"},s&&a.createElement("div",{className:C.announcementBarPlaceholder}),a.createElement(A,{className:C.announcementBarContent}),s&&a.createElement(k,{onClick:n,className:C.announcementBarClose}))}var T=n(9876),N=n(3104);var L=n(9532),O=n(5600);const P=a.createContext(null);function R(e){let{children:t}=e;const n=function(){const e=(0,T.M)(),t=(0,O.YL)(),[n,r]=(0,a.useState)(!1),o=null!==t.component,s=(0,L.ZC)(o);return(0,a.useEffect)((()=>{o&&!s&&r(!0)}),[o,s]),(0,a.useEffect)((()=>{o?e.shown||r(!0):r(!1)}),[e.shown,o]),(0,a.useMemo)((()=>[n,r]),[n])}();return a.createElement(P.Provider,{value:n},t)}function I(e){if(e.component){const t=e.component;return a.createElement(t,e.props)}}function M(){const e=(0,a.useContext)(P);if(!e)throw new L.dV("NavbarSecondaryMenuDisplayProvider");const[t,n]=e,r=(0,a.useCallback)((()=>n(!1)),[n]),o=(0,O.YL)();return(0,a.useMemo)((()=>({shown:t,hide:r,content:I(o)})),[r,o,t])}function D(e){let{header:t,primaryMenu:n,secondaryMenu:o}=e;const{shown:s}=M();return a.createElement("div",{className:"navbar-sidebar"},t,a.createElement("div",{className:(0,r.A)("navbar-sidebar__items",{"navbar-sidebar__items--show-secondary":s})},a.createElement("div",{className:"navbar-sidebar__item menu"},n),a.createElement("div",{className:"navbar-sidebar__item menu"},o)))}var F=n(5293),B=n(2303);function j(e){return a.createElement("svg",(0,i.A)({viewBox:"0 0 24 24",width:24,height:24},e),a.createElement("path",{fill:"currentColor",d:"M12,9c1.65,0,3,1.35,3,3s-1.35,3-3,3s-3-1.35-3-3S10.35,9,12,9 M12,7c-2.76,0-5,2.24-5,5s2.24,5,5,5s5-2.24,5-5 S14.76,7,12,7L12,7z M2,13l2,0c0.55,0,1-0.45,1-1s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S1.45,13,2,13z M20,13l2,0c0.55,0,1-0.45,1-1 s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S19.45,13,20,13z M11,2v2c0,0.55,0.45,1,1,1s1-0.45,1-1V2c0-0.55-0.45-1-1-1S11,1.45,11,2z M11,20v2c0,0.55,0.45,1,1,1s1-0.45,1-1v-2c0-0.55-0.45-1-1-1C11.45,19,11,19.45,11,20z M5.99,4.58c-0.39-0.39-1.03-0.39-1.41,0 c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0s0.39-1.03,0-1.41L5.99,4.58z M18.36,16.95 c-0.39-0.39-1.03-0.39-1.41,0c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0c0.39-0.39,0.39-1.03,0-1.41 L18.36,16.95z M19.42,5.99c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06c-0.39,0.39-0.39,1.03,0,1.41 s1.03,0.39,1.41,0L19.42,5.99z M7.05,18.36c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06 c-0.39,0.39-0.39,1.03,0,1.41s1.03,0.39,1.41,0L7.05,18.36z"}))}function z(e){return a.createElement("svg",(0,i.A)({viewBox:"0 0 24 24",width:24,height:24},e),a.createElement("path",{fill:"currentColor",d:"M9.37,5.51C9.19,6.15,9.1,6.82,9.1,7.5c0,4.08,3.32,7.4,7.4,7.4c0.68,0,1.35-0.09,1.99-0.27C17.45,17.19,14.93,19,12,19 c-3.86,0-7-3.14-7-7C5,9.07,6.81,6.55,9.37,5.51z M12,3c-4.97,0-9,4.03-9,9s4.03,9,9,9s9-4.03,9-9c0-0.46-0.04-0.92-0.1-1.36 c-0.98,1.37-2.58,2.26-4.4,2.26c-2.98,0-5.4-2.42-5.4-5.4c0-1.81,0.89-3.42,2.26-4.4C12.92,3.04,12.46,3,12,3L12,3z"}))}const $={toggle:"toggle_vylO",toggleButton:"toggleButton_gllP",darkToggleIcon:"darkToggleIcon_wfgR",lightToggleIcon:"lightToggleIcon_pyhR",toggleButtonDisabled:"toggleButtonDisabled_aARS"};function U(e){let{className:t,buttonClassName:n,value:o,onChange:s}=e;const i=(0,B.A)(),l=(0,c.T)({message:"Switch between dark and light mode (currently {mode})",id:"theme.colorToggle.ariaLabel",description:"The ARIA label for the navbar color mode toggle"},{mode:"dark"===o?(0,c.T)({message:"dark mode",id:"theme.colorToggle.ariaLabel.mode.dark",description:"The name for the dark color mode"}):(0,c.T)({message:"light mode",id:"theme.colorToggle.ariaLabel.mode.light",description:"The name for the light color mode"})});return a.createElement("div",{className:(0,r.A)($.toggle,t)},a.createElement("button",{className:(0,r.A)("clean-btn",$.toggleButton,!i&&$.toggleButtonDisabled,n),type:"button",onClick:()=>s("dark"===o?"light":"dark"),disabled:!i,title:l,"aria-label":l,"aria-live":"polite"},a.createElement(j,{className:(0,r.A)($.toggleIcon,$.lightToggleIcon)}),a.createElement(z,{className:(0,r.A)($.toggleIcon,$.darkToggleIcon)})))}const H=a.memo(U),V={darkNavbarColorModeToggle:"darkNavbarColorModeToggle_X3D1"};function G(e){let{className:t}=e;const n=(0,x.p)().navbar.style,r=(0,x.p)().colorMode.disableSwitch,{colorMode:o,setColorMode:s}=(0,F.G)();return r?null:a.createElement(H,{className:t,buttonClassName:"dark"===n?V.darkNavbarColorModeToggle:void 0,value:o,onChange:s})}var W=n(3465);function Y(){return a.createElement(W.A,{className:"navbar__brand",imageClassName:"navbar__logo",titleClassName:"navbar__title text--truncate"})}function K(){const e=(0,T.M)();return a.createElement("button",{type:"button","aria-label":(0,c.T)({id:"theme.docs.sidebar.closeSidebarButtonAriaLabel",message:"Close navigation bar",description:"The ARIA label for close button of mobile sidebar"}),className:"clean-btn navbar-sidebar__close",onClick:()=>e.toggle()},a.createElement(S,{color:"var(--ifm-color-emphasis-600)"}))}function Q(){return a.createElement("div",{className:"navbar-sidebar__brand"},a.createElement(Y,null),a.createElement(G,{className:"margin-right--md"}),a.createElement(K,null))}var X=n(5489),Z=n(6025),J=n(6654);function ee(e,t){return void 0!==e&&void 0!==t&&new RegExp(e,"gi").test(t)}var te=n(3186);function ne(e){let{activeBasePath:t,activeBaseRegex:n,to:r,href:o,label:s,html:l,isDropdownLink:c,prependBaseUrlToHref:u,...d}=e;const f=(0,Z.A)(r),p=(0,Z.A)(t),m=(0,Z.A)(o,{forcePrependBaseUrl:!0}),g=s&&o&&!(0,J.A)(o),h=l?{dangerouslySetInnerHTML:{__html:l}}:{children:a.createElement(a.Fragment,null,s,g&&a.createElement(te.A,c&&{width:12,height:12}))};return o?a.createElement(X.A,(0,i.A)({href:u?m:o},d,h)):a.createElement(X.A,(0,i.A)({to:f,isNavLink:!0},(t||n)&&{isActive:(e,t)=>n?ee(n,t.pathname):t.pathname.startsWith(p)},d,h))}function ae(e){let{className:t,isDropdownItem:n=!1,...o}=e;const s=a.createElement(ne,(0,i.A)({className:(0,r.A)(n?"dropdown__link":"navbar__item navbar__link",t),isDropdownLink:n},o));return n?a.createElement("li",null,s):s}function re(e){let{className:t,isDropdownItem:n,...o}=e;return a.createElement("li",{className:"menu__list-item"},a.createElement(ne,(0,i.A)({className:(0,r.A)("menu__link",t)},o)))}function oe(e){let{mobile:t=!1,position:n,...r}=e;const o=t?re:ae;return a.createElement(o,(0,i.A)({},r,{activeClassName:r.activeClassName??(t?"menu__link--active":"navbar__link--active")}))}var se=n(1422),ie=n(9169),le=n(4586);function ce(e,t){return e.some((e=>function(e,t){return!!(0,ie.ys)(e.to,t)||!!ee(e.activeBaseRegex,t)||!(!e.activeBasePath||!t.startsWith(e.activeBasePath))}(e,t)))}function ue(e){let{items:t,position:n,className:o,onClick:s,...l}=e;const c=(0,a.useRef)(null),[u,d]=(0,a.useState)(!1);return(0,a.useEffect)((()=>{const e=e=>{c.current&&!c.current.contains(e.target)&&d(!1)};return document.addEventListener("mousedown",e),document.addEventListener("touchstart",e),document.addEventListener("focusin",e),()=>{document.removeEventListener("mousedown",e),document.removeEventListener("touchstart",e),document.removeEventListener("focusin",e)}}),[c]),a.createElement("div",{ref:c,className:(0,r.A)("navbar__item","dropdown","dropdown--hoverable",{"dropdown--right":"right"===n,"dropdown--show":u})},a.createElement(ne,(0,i.A)({"aria-haspopup":"true","aria-expanded":u,role:"button",href:l.to?void 0:"#",className:(0,r.A)("navbar__link",o)},l,{onClick:l.to?void 0:e=>e.preventDefault(),onKeyDown:e=>{"Enter"===e.key&&(e.preventDefault(),d(!u))}}),l.children??l.label),a.createElement("ul",{className:"dropdown__menu"},t.map(((e,t)=>a.createElement(ke,(0,i.A)({isDropdownItem:!0,activeClassName:"dropdown__link--active"},e,{key:t}))))))}function de(e){let{items:t,className:n,position:o,onClick:s,...c}=e;const u=function(){const{siteConfig:{baseUrl:e}}=(0,le.A)(),{pathname:t}=(0,l.zy)();return t.replace(e,"/")}(),d=ce(t,u),{collapsed:f,toggleCollapsed:p,setCollapsed:m}=(0,se.u)({initialState:()=>!d});return(0,a.useEffect)((()=>{d&&m(!d)}),[u,d,m]),a.createElement("li",{className:(0,r.A)("menu__list-item",{"menu__list-item--collapsed":f})},a.createElement(ne,(0,i.A)({role:"button",className:(0,r.A)("menu__link menu__link--sublist menu__link--sublist-caret",n)},c,{onClick:e=>{e.preventDefault(),p()}}),c.children??c.label),a.createElement(se.N,{lazy:!0,as:"ul",className:"menu__list",collapsed:f},t.map(((e,t)=>a.createElement(ke,(0,i.A)({mobile:!0,isDropdownItem:!0,onClick:s,activeClassName:"menu__link--active"},e,{key:t}))))))}function fe(e){let{mobile:t=!1,...n}=e;const r=t?de:ue;return a.createElement(r,n)}var pe=n(2131);function me(e){let{width:t=20,height:n=20,...r}=e;return a.createElement("svg",(0,i.A)({viewBox:"0 0 24 24",width:t,height:n,"aria-hidden":!0},r),a.createElement("path",{fill:"currentColor",d:"M12.87 15.07l-2.54-2.51.03-.03c1.74-1.94 2.98-4.17 3.71-6.53H17V4h-7V2H8v2H1v1.99h11.17C11.5 7.92 10.44 9.75 9 11.35 8.07 10.32 7.3 9.19 6.69 8h-2c.73 1.63 1.73 3.17 2.98 4.56l-5.09 5.02L4 19l5-5 3.11 3.11.76-2.04zM18.5 10h-2L12 22h2l1.12-3h4.75L21 22h2l-4.5-12zm-2.62 7l1.62-4.33L19.12 17h-3.24z"}))}const ge="iconLanguage_nlXk";var he=n(418);const be={searchBox:"searchBox_ZlJk"};function ye(e){let{children:t,className:n}=e;return a.createElement("div",{className:(0,r.A)(n,be.searchBox)},t)}var ve=n(4070),xe=n(1754);var we=n(5597);const Se=e=>e.docs.find((t=>t.id===e.mainDocId));const Ee={default:oe,localeDropdown:function(e){let{mobile:t,dropdownItemsBefore:n,dropdownItemsAfter:r,...o}=e;const{i18n:{currentLocale:s,locales:u,localeConfigs:d}}=(0,le.A)(),f=(0,pe.o)(),{search:p,hash:m}=(0,l.zy)(),g=[...n,...u.map((e=>{const n=`${`pathname://${f.createUrl({locale:e,fullyQualified:!1})}`}${p}${m}`;return{label:d[e].label,lang:d[e].htmlLang,to:n,target:"_self",autoAddBaseUrl:!1,className:e===s?t?"menu__link--active":"dropdown__link--active":""}})),...r],h=t?(0,c.T)({message:"Languages",id:"theme.navbar.mobileLanguageDropdown.label",description:"The label for the mobile language switcher dropdown"}):d[s].label;return a.createElement(fe,(0,i.A)({},o,{mobile:t,label:a.createElement(a.Fragment,null,a.createElement(me,{className:ge}),h),items:g}))},search:function(e){let{mobile:t,className:n}=e;return t?null:a.createElement(ye,{className:n},a.createElement(he.A,null))},dropdown:fe,html:function(e){let{value:t,className:n,mobile:o=!1,isDropdownItem:s=!1}=e;const i=s?"li":"div";return a.createElement(i,{className:(0,r.A)({navbar__item:!o&&!s,"menu__list-item":o},n),dangerouslySetInnerHTML:{__html:t}})},doc:function(e){let{docId:t,label:n,docsPluginId:r,...o}=e;const{activeDoc:s}=(0,ve.zK)(r),l=(0,xe.QB)(t,r);return null===l?null:a.createElement(oe,(0,i.A)({exact:!0},o,{isActive:()=>s?.path===l.path||!!s?.sidebar&&s.sidebar===l.sidebar,label:n??l.id,to:l.path}))},docSidebar:function(e){let{sidebarId:t,label:n,docsPluginId:r,...o}=e;const{activeDoc:s}=(0,ve.zK)(r),l=(0,xe.fW)(t,r).link;if(!l)throw new Error(`DocSidebarNavbarItem: Sidebar with ID "${t}" doesn't have anything to be linked to.`);return a.createElement(oe,(0,i.A)({exact:!0},o,{isActive:()=>s?.sidebar===t,label:n??l.label,to:l.path}))},docsVersion:function(e){let{label:t,to:n,docsPluginId:r,...o}=e;const s=(0,xe.Vd)(r)[0],l=t??s.label,c=n??(e=>e.docs.find((t=>t.id===e.mainDocId)))(s).path;return a.createElement(oe,(0,i.A)({},o,{label:l,to:c}))},docsVersionDropdown:function(e){let{mobile:t,docsPluginId:n,dropdownActiveClassDisabled:r,dropdownItemsBefore:o,dropdownItemsAfter:s,...u}=e;const{search:d,hash:f}=(0,l.zy)(),p=(0,ve.zK)(n),m=(0,ve.jh)(n),{savePreferredVersionName:g}=(0,we.g1)(n),h=[...o,...m.map((e=>{const t=p.alternateDocVersions[e.name]??Se(e);return{label:e.label,to:`${t.path}${d}${f}`,isActive:()=>e===p.activeVersion,onClick:()=>g(e.name)}})),...s],b=(0,xe.Vd)(n)[0],y=t&&h.length>1?(0,c.T)({id:"theme.navbar.mobileVersionsDropdown.label",message:"Versions",description:"The label for the navbar versions dropdown on mobile view"}):b.label,v=t&&h.length>1?void 0:Se(b).path;return h.length<=1?a.createElement(oe,(0,i.A)({},u,{mobile:t,label:y,to:v,isActive:r?()=>!1:void 0})):a.createElement(fe,(0,i.A)({},u,{mobile:t,label:y,to:v,items:h,isActive:r?()=>!1:void 0}))}};function ke(e){let{type:t,...n}=e;const r=function(e,t){return e&&"default"!==e?e:"items"in t?"dropdown":"default"}(t,n),o=Ee[r];if(!o)throw new Error(`No NavbarItem component found for type "${t}".`);return a.createElement(o,n)}function _e(){const e=(0,T.M)(),t=(0,x.p)().navbar.items;return a.createElement("ul",{className:"menu__list"},t.map(((t,n)=>a.createElement(ke,(0,i.A)({mobile:!0},t,{onClick:()=>e.toggle(),key:n})))))}function Ae(e){return a.createElement("button",(0,i.A)({},e,{type:"button",className:"clean-btn navbar-sidebar__back"}),a.createElement(c.A,{id:"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel",description:"The label of the back button to return to main menu, inside the mobile navbar sidebar secondary menu (notably used to display the docs sidebar)"},"\u2190 Back to main menu"))}function Ce(){const e=0===(0,x.p)().navbar.items.length,t=M();return a.createElement(a.Fragment,null,!e&&a.createElement(Ae,{onClick:()=>t.hide()}),t.content)}function qe(){const e=(0,T.M)();var t;return void 0===(t=e.shown)&&(t=!0),(0,a.useEffect)((()=>(document.body.style.overflow=t?"hidden":"visible",()=>{document.body.style.overflow="visible"})),[t]),e.shouldRender?a.createElement(D,{header:a.createElement(Q,null),primaryMenu:a.createElement(_e,null),secondaryMenu:a.createElement(Ce,null)}):null}const Te={navbarHideable:"navbarHideable_m1mJ",navbarHidden:"navbarHidden_jGov"};function Ne(e){return a.createElement("div",(0,i.A)({role:"presentation"},e,{className:(0,r.A)("navbar-sidebar__backdrop",e.className)}))}function Le(e){let{children:t}=e;const{navbar:{hideOnScroll:n,style:o}}=(0,x.p)(),s=(0,T.M)(),{navbarRef:i,isNavbarVisible:l}=function(e){const[t,n]=(0,a.useState)(e),r=(0,a.useRef)(!1),o=(0,a.useRef)(0),s=(0,a.useCallback)((e=>{null!==e&&(o.current=e.getBoundingClientRect().height)}),[]);return(0,N.Mq)(((t,a)=>{let{scrollY:s}=t;if(!e)return;if(s<o.current)return void n(!0);if(r.current)return void(r.current=!1);const i=a?.scrollY,l=document.documentElement.scrollHeight-o.current,c=window.innerHeight;i&&s>=i?n(!1):s+c<l&&n(!0)})),(0,u.$)((t=>{if(!e)return;const a=t.location.hash;if(a?document.getElementById(a.substring(1)):void 0)return r.current=!0,void n(!1);n(!0)})),{navbarRef:s,isNavbarVisible:t}}(n);return a.createElement("nav",{ref:i,"aria-label":(0,c.T)({id:"theme.NavBar.navAriaLabel",message:"Main",description:"The ARIA label for the main navigation"}),className:(0,r.A)("navbar","navbar--fixed-top",n&&[Te.navbarHideable,!l&&Te.navbarHidden],{"navbar--dark":"dark"===o,"navbar--primary":"primary"===o,"navbar-sidebar--show":s.shown})},t,a.createElement(Ne,{onClick:s.toggle}),a.createElement(qe,null))}var Oe=n(440);const Pe={errorBoundaryError:"errorBoundaryError_a6uf"};function Re(e){return a.createElement("button",(0,i.A)({type:"button"},e),a.createElement(c.A,{id:"theme.ErrorPageContent.tryAgain",description:"The label of the button to try again rendering when the React error boundary captures an error"},"Try again"))}function Ie(e){let{error:t}=e;const n=(0,Oe.getErrorCausalChain)(t).map((e=>e.message)).join("\n\nCause:\n");return a.createElement("p",{className:Pe.errorBoundaryError},n)}class Me extends a.Component{componentDidCatch(e,t){throw this.props.onError(e,t)}render(){return this.props.children}}const De="right";function Fe(e){let{width:t=30,height:n=30,className:r,...o}=e;return a.createElement("svg",(0,i.A)({className:r,width:t,height:n,viewBox:"0 0 30 30","aria-hidden":"true"},o),a.createElement("path",{stroke:"currentColor",strokeLinecap:"round",strokeMiterlimit:"10",strokeWidth:"2",d:"M4 7h22M4 15h22M4 23h22"}))}function Be(){const{toggle:e,shown:t}=(0,T.M)();return a.createElement("button",{onClick:e,"aria-label":(0,c.T)({id:"theme.docs.sidebar.toggleSidebarButtonAriaLabel",message:"Toggle navigation bar",description:"The ARIA label for hamburger menu button of mobile navigation"}),"aria-expanded":t,className:"navbar__toggle clean-btn",type:"button"},a.createElement(Fe,null))}const je={colorModeToggle:"colorModeToggle_DEke"};function ze(e){let{items:t}=e;return a.createElement(a.Fragment,null,t.map(((e,t)=>a.createElement(Me,{key:t,onError:t=>new Error(`A theme navbar item failed to render.\nPlease double-check the following navbar item (themeConfig.navbar.items) of your Docusaurus config:\n${JSON.stringify(e,null,2)}`,{cause:t})},a.createElement(ke,e)))))}function $e(e){let{left:t,right:n}=e;return a.createElement("div",{className:"navbar__inner"},a.createElement("div",{className:"navbar__items"},t),a.createElement("div",{className:"navbar__items navbar__items--right"},n))}function Ue(){const e=(0,T.M)(),t=(0,x.p)().navbar.items,[n,r]=function(e){function t(e){return"left"===(e.position??De)}return[e.filter(t),e.filter((e=>!t(e)))]}(t),o=t.find((e=>"search"===e.type));return a.createElement($e,{left:a.createElement(a.Fragment,null,!e.disabled&&a.createElement(Be,null),a.createElement(Y,null),a.createElement(ze,{items:n})),right:a.createElement(a.Fragment,null,a.createElement(ze,{items:r}),a.createElement(G,{className:je.colorModeToggle}),!o&&a.createElement(ye,null,a.createElement(he.A,null)))})}function He(){return a.createElement(Le,null,a.createElement(Ue,null))}function Ve(e){let{item:t}=e;const{to:n,href:r,label:o,prependBaseUrlToHref:s,...l}=t,c=(0,Z.A)(n),u=(0,Z.A)(r,{forcePrependBaseUrl:!0});return a.createElement(X.A,(0,i.A)({className:"footer__link-item"},r?{href:s?u:r}:{to:c},l),o,r&&!(0,J.A)(r)&&a.createElement(te.A,null))}function Ge(e){let{item:t}=e;return t.html?a.createElement("li",{className:"footer__item",dangerouslySetInnerHTML:{__html:t.html}}):a.createElement("li",{key:t.href??t.to,className:"footer__item"},a.createElement(Ve,{item:t}))}function We(e){let{column:t}=e;return a.createElement("div",{className:"col footer__col"},a.createElement("div",{className:"footer__title"},t.title),a.createElement("ul",{className:"footer__items clean-list"},t.items.map(((e,t)=>a.createElement(Ge,{key:t,item:e})))))}function Ye(e){let{columns:t}=e;return a.createElement("div",{className:"row footer__links"},t.map(((e,t)=>a.createElement(We,{key:t,column:e}))))}function Ke(){return a.createElement("span",{className:"footer__link-separator"},"\xb7")}function Qe(e){let{item:t}=e;return t.html?a.createElement("span",{className:"footer__link-item",dangerouslySetInnerHTML:{__html:t.html}}):a.createElement(Ve,{item:t})}function Xe(e){let{links:t}=e;return a.createElement("div",{className:"footer__links text--center"},a.createElement("div",{className:"footer__links"},t.map(((e,n)=>a.createElement(a.Fragment,{key:n},a.createElement(Qe,{item:e}),t.length!==n+1&&a.createElement(Ke,null))))))}function Ze(e){let{links:t}=e;return function(e){return"title"in e[0]}(t)?a.createElement(Ye,{columns:t}):a.createElement(Xe,{links:t})}var Je=n(1653);const et={footerLogoLink:"footerLogoLink_BH7S"};function tt(e){let{logo:t}=e;const{withBaseUrl:n}=(0,Z.h)(),o={light:n(t.src),dark:n(t.srcDark??t.src)};return a.createElement(Je.A,{className:(0,r.A)("footer__logo",t.className),alt:t.alt,sources:o,width:t.width,height:t.height,style:t.style})}function nt(e){let{logo:t}=e;return t.href?a.createElement(X.A,{href:t.href,className:et.footerLogoLink,target:t.target},a.createElement(tt,{logo:t})):a.createElement(tt,{logo:t})}function at(e){let{copyright:t}=e;return a.createElement("div",{className:"footer__copyright",dangerouslySetInnerHTML:{__html:t}})}function rt(e){let{style:t,links:n,logo:o,copyright:s}=e;return a.createElement("footer",{className:(0,r.A)("footer",{"footer--dark":"dark"===t})},a.createElement("div",{className:"container container-fluid"},n,(o||s)&&a.createElement("div",{className:"footer__bottom text--center"},o&&a.createElement("div",{className:"margin-bottom--sm"},o),s)))}function ot(){const{footer:e}=(0,x.p)();if(!e)return null;const{copyright:t,links:n,logo:r,style:o}=e;return a.createElement(rt,{style:o,links:n&&n.length>0&&a.createElement(Ze,{links:n}),logo:r&&a.createElement(nt,{logo:r}),copyright:t&&a.createElement(at,{copyright:t})})}const st=a.memo(ot),it=(0,L.fM)([F.a,w.oq,N.Tv,we.VQ,s.Jx,function(e){let{children:t}=e;return a.createElement(O.y_,null,a.createElement(T.e,null,a.createElement(R,null,t)))}]);function lt(e){let{children:t}=e;return a.createElement(it,null,t)}function ct(e){let{error:t,tryAgain:n}=e;return a.createElement("main",{className:"container margin-vert--xl"},a.createElement("div",{className:"row"},a.createElement("div",{className:"col col--6 col--offset-3"},a.createElement("h1",{className:"hero__title"},a.createElement(c.A,{id:"theme.ErrorPageContent.title",description:"The title of the fallback page when the page crashed"},"This page crashed.")),a.createElement("div",{className:"margin-vert--lg"},a.createElement(Re,{onClick:n,className:"button button--primary shadow--lw"})),a.createElement("hr",null),a.createElement("div",{className:"margin-vert--md"},a.createElement(Ie,{error:t})))))}const ut={mainWrapper:"mainWrapper_z2l0"};function dt(e){const{children:t,noFooter:n,wrapperClassName:i,title:l,description:c}=e;return(0,b.J)(),a.createElement(lt,null,a.createElement(s.be,{title:l,description:c}),a.createElement(v,null),a.createElement(q,null),a.createElement(He,null),a.createElement("div",{id:d,className:(0,r.A)(h.G.wrapper.main,ut.mainWrapper,i)},a.createElement(o.A,{fallback:e=>a.createElement(ct,e)},t)),!n&&a.createElement(st,null))}},3465:(e,t,n)=>{"use strict";n.d(t,{A:()=>d});var a=n(8168),r=n(6540),o=n(5489),s=n(6025),i=n(4586),l=n(6342),c=n(1653);function u(e){let{logo:t,alt:n,imageClassName:a}=e;const o={light:(0,s.A)(t.src),dark:(0,s.A)(t.srcDark||t.src)},i=r.createElement(c.A,{className:t.className,sources:o,height:t.height,width:t.width,alt:n,style:t.style});return a?r.createElement("div",{className:a},i):i}function d(e){const{siteConfig:{title:t}}=(0,i.A)(),{navbar:{title:n,logo:c}}=(0,l.p)(),{imageClassName:d,titleClassName:f,...p}=e,m=(0,s.A)(c?.href||"/"),g=n?"":t,h=c?.alt??g;return r.createElement(o.A,(0,a.A)({to:m},p,c?.target&&{target:c.target}),c&&r.createElement(u,{logo:c,alt:h,imageClassName:d}),null!=n&&r.createElement("b",{className:f},n))}},1463:(e,t,n)=>{"use strict";n.d(t,{A:()=>o});var a=n(6540),r=n(5260);function o(e){let{locale:t,version:n,tag:o}=e;const s=t;return a.createElement(r.A,null,t&&a.createElement("meta",{name:"docusaurus_locale",content:t}),n&&a.createElement("meta",{name:"docusaurus_version",content:n}),o&&a.createElement("meta",{name:"docusaurus_tag",content:o}),s&&a.createElement("meta",{name:"docsearch:language",content:s}),n&&a.createElement("meta",{name:"docsearch:version",content:n}),o&&a.createElement("meta",{name:"docsearch:docusaurus_tag",content:o}))}},1653:(e,t,n)=>{"use strict";n.d(t,{A:()=>c});var a=n(8168),r=n(6540),o=n(53),s=n(2303),i=n(5293);const l={themedImage:"themedImage_ToTc","themedImage--light":"themedImage--light_HNdA","themedImage--dark":"themedImage--dark_i4oU"};function c(e){const t=(0,s.A)(),{colorMode:n}=(0,i.G)(),{sources:c,className:u,alt:d,...f}=e,p=t?"dark"===n?["dark"]:["light"]:["light","dark"];return r.createElement(r.Fragment,null,p.map((e=>r.createElement("img",(0,a.A)({key:e,src:c[e],alt:d,className:(0,o.A)(l.themedImage,l[`themedImage--${e}`],u)},f)))))}},1422:(e,t,n)=>{"use strict";n.d(t,{N:()=>h,u:()=>l});var a=n(8168),r=n(6540),o=n(8193),s=n(3109);const i="ease-in-out";function l(e){let{initialState:t}=e;const[n,a]=(0,r.useState)(t??!1),o=(0,r.useCallback)((()=>{a((e=>!e))}),[]);return{collapsed:n,setCollapsed:a,toggleCollapsed:o}}const c={display:"none",overflow:"hidden",height:"0px"},u={display:"block",overflow:"visible",height:"auto"};function d(e,t){const n=t?c:u;e.style.display=n.display,e.style.overflow=n.overflow,e.style.height=n.height}function f(e){let{collapsibleRef:t,collapsed:n,animation:a}=e;const o=(0,r.useRef)(!1);(0,r.useEffect)((()=>{const e=t.current;function r(){const t=e.scrollHeight,n=a?.duration??function(e){if((0,s.O)())return 1;const t=e/36;return Math.round(10*(4+15*t**.25+t/5))}(t);return{transition:`height ${n}ms ${a?.easing??i}`,height:`${t}px`}}function l(){const t=r();e.style.transition=t.transition,e.style.height=t.height}if(!o.current)return d(e,n),void(o.current=!0);return e.style.willChange="height",function(){const t=requestAnimationFrame((()=>{n?(l(),requestAnimationFrame((()=>{e.style.height=c.height,e.style.overflow=c.overflow}))):(e.style.display="block",requestAnimationFrame((()=>{l()})))}));return()=>cancelAnimationFrame(t)}()}),[t,n,a])}function p(e){if(!o.A.canUseDOM)return e?c:u}function m(e){let{as:t="div",collapsed:n,children:a,animation:o,onCollapseTransitionEnd:s,className:i,disableSSRStyle:l}=e;const c=(0,r.useRef)(null);return f({collapsibleRef:c,collapsed:n,animation:o}),r.createElement(t,{ref:c,style:l?void 0:p(n),onTransitionEnd:e=>{"height"===e.propertyName&&(d(c.current,n),s?.(n))},className:i},a)}function g(e){let{collapsed:t,...n}=e;const[o,s]=(0,r.useState)(!t),[i,l]=(0,r.useState)(t);return(0,r.useLayoutEffect)((()=>{t||s(!0)}),[t]),(0,r.useLayoutEffect)((()=>{o&&l(t)}),[o,t]),o?r.createElement(m,(0,a.A)({},n,{collapsed:i})):null}function h(e){let{lazy:t,...n}=e;const a=t?g:m;return r.createElement(a,n)}},5041:(e,t,n)=>{"use strict";n.d(t,{Mj:()=>m,oq:()=>p});var a=n(6540),r=n(2303),o=n(9466),s=n(9532),i=n(6342);const l=(0,o.Wf)("docusaurus.announcement.dismiss"),c=(0,o.Wf)("docusaurus.announcement.id"),u=()=>"true"===l.get(),d=e=>l.set(String(e)),f=a.createContext(null);function p(e){let{children:t}=e;const n=function(){const{announcementBar:e}=(0,i.p)(),t=(0,r.A)(),[n,o]=(0,a.useState)((()=>!!t&&u()));(0,a.useEffect)((()=>{o(u())}),[]);const s=(0,a.useCallback)((()=>{d(!0),o(!0)}),[]);return(0,a.useEffect)((()=>{if(!e)return;const{id:t}=e;let n=c.get();"annoucement-bar"===n&&(n="announcement-bar");const a=t!==n;c.set(t),a&&d(!1),!a&&u()||o(!1)}),[e]),(0,a.useMemo)((()=>({isActive:!!e&&!n,close:s})),[e,n,s])}();return a.createElement(f.Provider,{value:n},t)}function m(){const e=(0,a.useContext)(f);if(!e)throw new s.dV("AnnouncementBarProvider");return e}},5293:(e,t,n)=>{"use strict";n.d(t,{G:()=>h,a:()=>g});var a=n(6540),r=n(8193),o=n(9532),s=n(9466),i=n(6342);const l=a.createContext(void 0),c="theme",u=(0,s.Wf)(c),d={light:"light",dark:"dark"},f=e=>e===d.dark?d.dark:d.light,p=e=>r.A.canUseDOM?f(document.documentElement.getAttribute("data-theme")):f(e),m=e=>{u.set(f(e))};function g(e){let{children:t}=e;const n=function(){const{colorMode:{defaultMode:e,disableSwitch:t,respectPrefersColorScheme:n}}=(0,i.p)(),[r,o]=(0,a.useState)(p(e));(0,a.useEffect)((()=>{t&&u.del()}),[t]);const s=(0,a.useCallback)((function(t,a){void 0===a&&(a={});const{persist:r=!0}=a;t?(o(t),r&&m(t)):(o(n?window.matchMedia("(prefers-color-scheme: dark)").matches?d.dark:d.light:e),u.del())}),[n,e]);(0,a.useEffect)((()=>{document.documentElement.setAttribute("data-theme",f(r))}),[r]),(0,a.useEffect)((()=>{if(t)return;const e=e=>{if(e.key!==c)return;const t=u.get();null!==t&&s(f(t))};return window.addEventListener("storage",e),()=>window.removeEventListener("storage",e)}),[t,s]);const l=(0,a.useRef)(!1);return(0,a.useEffect)((()=>{if(t&&!n)return;const e=window.matchMedia("(prefers-color-scheme: dark)"),a=()=>{window.matchMedia("print").matches||l.current?l.current=window.matchMedia("print").matches:s(null)};return e.addListener(a),()=>e.removeListener(a)}),[s,t,n]),(0,a.useMemo)((()=>({colorMode:r,setColorMode:s,get isDarkTheme(){return r===d.dark},setLightTheme(){s(d.light)},setDarkTheme(){s(d.dark)}})),[r,s])}();return a.createElement(l.Provider,{value:n},t)}function h(){const e=(0,a.useContext)(l);if(null==e)throw new o.dV("ColorModeProvider","Please see https://docusaurus.io/docs/api/themes/configuration#use-color-mode.");return e}},5597:(e,t,n)=>{"use strict";n.d(t,{VQ:()=>h,g1:()=>y});var a=n(6540),r=n(4070),o=n(7065),s=n(6342),i=n(1754),l=n(9532),c=n(9466);const u=e=>`docs-preferred-version-${e}`,d={save:(e,t,n)=>{(0,c.Wf)(u(e),{persistence:t}).set(n)},read:(e,t)=>(0,c.Wf)(u(e),{persistence:t}).get(),clear:(e,t)=>{(0,c.Wf)(u(e),{persistence:t}).del()}},f=e=>Object.fromEntries(e.map((e=>[e,{preferredVersionName:null}])));const p=a.createContext(null);function m(){const e=(0,r.Gy)(),t=(0,s.p)().docs.versionPersistence,n=(0,a.useMemo)((()=>Object.keys(e)),[e]),[o,i]=(0,a.useState)((()=>f(n)));(0,a.useEffect)((()=>{i(function(e){let{pluginIds:t,versionPersistence:n,allDocsData:a}=e;function r(e){const t=d.read(e,n);return a[e].versions.some((e=>e.name===t))?{preferredVersionName:t}:(d.clear(e,n),{preferredVersionName:null})}return Object.fromEntries(t.map((e=>[e,r(e)])))}({allDocsData:e,versionPersistence:t,pluginIds:n}))}),[e,t,n]);return[o,(0,a.useMemo)((()=>({savePreferredVersion:function(e,n){d.save(e,t,n),i((t=>({...t,[e]:{preferredVersionName:n}})))}})),[t])]}function g(e){let{children:t}=e;const n=m();return a.createElement(p.Provider,{value:n},t)}function h(e){let{children:t}=e;return i.C5?a.createElement(g,null,t):a.createElement(a.Fragment,null,t)}function b(){const e=(0,a.useContext)(p);if(!e)throw new l.dV("DocsPreferredVersionContextProvider");return e}function y(e){void 0===e&&(e=o.W);const t=(0,r.ht)(e),[n,s]=b(),{preferredVersionName:i}=n[e];return{preferredVersion:t.versions.find((e=>e.name===i))??null,savePreferredVersionName:(0,a.useCallback)((t=>{s.savePreferredVersion(e,t)}),[s,e])}}},6588:(e,t,n)=>{"use strict";n.d(t,{V:()=>i,t:()=>l});var a=n(6540),r=n(9532);const o=Symbol("EmptyContext"),s=a.createContext(o);function i(e){let{children:t,name:n,items:r}=e;const o=(0,a.useMemo)((()=>n&&r?{name:n,items:r}:null),[n,r]);return a.createElement(s.Provider,{value:o},t)}function l(){const e=(0,a.useContext)(s);if(e===o)throw new r.dV("DocsSidebarProvider");return e}},9876:(e,t,n)=>{"use strict";n.d(t,{e:()=>f,M:()=>p});var a=n(6540),r=n(5600),o=n(4581),s=n(6347),i=(n(9888),n(9532));function l(e){!function(e){const t=(0,s.W6)(),n=(0,i._q)(e);(0,a.useEffect)((()=>t.block(((e,t)=>n(e,t)))),[t,n])}(((t,n)=>{if("POP"===n)return e(t,n)}))}var c=n(6342);const u=a.createContext(void 0);function d(){const e=function(){const e=(0,r.YL)(),{items:t}=(0,c.p)().navbar;return 0===t.length&&!e.component}(),t=(0,o.l)(),n=!e&&"mobile"===t,[s,i]=(0,a.useState)(!1);l((()=>{if(s)return i(!1),!1}));const u=(0,a.useCallback)((()=>{i((e=>!e))}),[]);return(0,a.useEffect)((()=>{"desktop"===t&&i(!1)}),[t]),(0,a.useMemo)((()=>({disabled:e,shouldRender:n,toggle:u,shown:s})),[e,n,u,s])}function f(e){let{children:t}=e;const n=d();return a.createElement(u.Provider,{value:n},t)}function p(){const e=a.useContext(u);if(void 0===e)throw new i.dV("NavbarMobileSidebarProvider");return e}},5600:(e,t,n)=>{"use strict";n.d(t,{GX:()=>l,YL:()=>i,y_:()=>s});var a=n(6540),r=n(9532);const o=a.createContext(null);function s(e){let{children:t}=e;const n=(0,a.useState)({component:null,props:null});return a.createElement(o.Provider,{value:n},t)}function i(){const e=(0,a.useContext)(o);if(!e)throw new r.dV("NavbarSecondaryMenuContentProvider");return e[0]}function l(e){let{component:t,props:n}=e;const s=(0,a.useContext)(o);if(!s)throw new r.dV("NavbarSecondaryMenuContentProvider");const[,i]=s,l=(0,r.Be)(n);return(0,a.useEffect)((()=>{i({component:t,props:l})}),[i,t,l]),(0,a.useEffect)((()=>()=>i({component:null,props:null})),[i]),null}},4090:(e,t,n)=>{"use strict";n.d(t,{w:()=>r,J:()=>o});var a=n(6540);const r="navigation-with-keyboard";function o(){(0,a.useEffect)((()=>{function e(e){"keydown"===e.type&&"Tab"===e.key&&document.body.classList.add(r),"mousedown"===e.type&&document.body.classList.remove(r)}return document.addEventListener("keydown",e),document.addEventListener("mousedown",e),()=>{document.body.classList.remove(r),document.removeEventListener("keydown",e),document.removeEventListener("mousedown",e)}}),[])}},4581:(e,t,n)=>{"use strict";n.d(t,{l:()=>c});var a=n(6540),r=n(8193);const o={desktop:"desktop",mobile:"mobile",ssr:"ssr"},s=996;function i(){return r.A.canUseDOM?window.innerWidth>s?o.desktop:o.mobile:o.ssr}const l=!1;function c(){const[e,t]=(0,a.useState)((()=>l?"ssr":i()));return(0,a.useEffect)((()=>{function e(){t(i())}const n=l?window.setTimeout(e,1e3):void 0;return window.addEventListener("resize",e),()=>{window.removeEventListener("resize",e),clearTimeout(n)}}),[]),e}},7559:(e,t,n)=>{"use strict";n.d(t,{G:()=>a});const a={page:{blogListPage:"blog-list-page",blogPostPage:"blog-post-page",blogTagsListPage:"blog-tags-list-page",blogTagPostListPage:"blog-tags-post-list-page",docsDocPage:"docs-doc-page",docsTagsListPage:"docs-tags-list-page",docsTagDocListPage:"docs-tags-doc-list-page",mdxPage:"mdx-page"},wrapper:{main:"main-wrapper",blogPages:"blog-wrapper",docsPages:"docs-wrapper",mdxPages:"mdx-wrapper"},common:{editThisPage:"theme-edit-this-page",lastUpdated:"theme-last-updated",backToTopButton:"theme-back-to-top-button",codeBlock:"theme-code-block",admonition:"theme-admonition",admonitionType:e=>`theme-admonition-${e}`},layout:{},docs:{docVersionBanner:"theme-doc-version-banner",docVersionBadge:"theme-doc-version-badge",docBreadcrumbs:"theme-doc-breadcrumbs",docMarkdown:"theme-doc-markdown",docTocMobile:"theme-doc-toc-mobile",docTocDesktop:"theme-doc-toc-desktop",docFooter:"theme-doc-footer",docFooterTagsRow:"theme-doc-footer-tags-row",docFooterEditMetaRow:"theme-doc-footer-edit-meta-row",docSidebarContainer:"theme-doc-sidebar-container",docSidebarMenu:"theme-doc-sidebar-menu",docSidebarItemCategory:"theme-doc-sidebar-item-category",docSidebarItemLink:"theme-doc-sidebar-item-link",docSidebarItemCategoryLevel:e=>`theme-doc-sidebar-item-category-level-${e}`,docSidebarItemLinkLevel:e=>`theme-doc-sidebar-item-link-level-${e}`},blog:{}}},3109:(e,t,n)=>{"use strict";function a(){return window.matchMedia("(prefers-reduced-motion: reduce)").matches}n.d(t,{O:()=>a})},1754:(e,t,n)=>{"use strict";n.d(t,{_o:()=>f,w8:()=>g,C5:()=>d,mz:()=>w,Vd:()=>y,QB:()=>x,fW:()=>v,OF:()=>b});var a=n(6540),r=n(6347),o=n(2831),s=n(4070),i=n(5597),l=n(6588);function c(e){return Array.from(new Set(e))}var u=n(9169);const d=!!s.Gy;function f(e){if(e.href)return e.href;for(const t of e.items){if("link"===t.type)return t.href;if("category"===t.type){const e=f(t);if(e)return e}}}const p=(e,t)=>void 0!==e&&(0,u.ys)(e,t),m=(e,t)=>e.some((e=>g(e,t)));function g(e,t){return"link"===e.type?p(e.href,t):"category"===e.type&&(p(e.href,t)||m(e.items,t))}function h(e){let{sidebarItems:t,pathname:n,onlyCategories:a=!1}=e;const r=[];return function e(t){for(const o of t)if("category"===o.type&&((0,u.ys)(o.href,n)||e(o.items))||"link"===o.type&&(0,u.ys)(o.href,n)){return a&&"category"!==o.type||r.unshift(o),!0}return!1}(t),r}function b(){const e=(0,l.t)(),{pathname:t}=(0,r.zy)(),n=(0,s.vT)()?.pluginData.breadcrumbs;return!1!==n&&e?h({sidebarItems:e.items,pathname:t}):null}function y(e){const{activeVersion:t}=(0,s.zK)(e),{preferredVersion:n}=(0,i.g1)(e),r=(0,s.r7)(e);return(0,a.useMemo)((()=>c([t,n,r].filter(Boolean))),[t,n,r])}function v(e,t){const n=y(t);return(0,a.useMemo)((()=>{const t=n.flatMap((e=>e.sidebars?Object.entries(e.sidebars):[])),a=t.find((t=>t[0]===e));if(!a)throw new Error(`Can't find any sidebar with id "${e}" in version${n.length>1?"s":""} ${n.map((e=>e.name)).join(", ")}".\nAvailable sidebar ids are:\n- ${t.map((e=>e[0])).join("\n- ")}`);return a[1]}),[e,n])}function x(e,t){const n=y(t);return(0,a.useMemo)((()=>{const t=n.flatMap((e=>e.docs)),a=t.find((t=>t.id===e));if(!a){if(n.flatMap((e=>e.draftIds)).includes(e))return null;throw new Error(`Couldn't find any doc with id "${e}" in version${n.length>1?"s":""} "${n.map((e=>e.name)).join(", ")}".\nAvailable doc ids are:\n- ${c(t.map((e=>e.id))).join("\n- ")}`)}return a}),[e,n])}function w(e){let{route:t,versionMetadata:n}=e;const a=(0,r.zy)(),s=t.routes,i=s.find((e=>(0,r.B6)(a.pathname,e)));if(!i)return null;const l=i.sidebar,c=l?n.docsSidebars[l]:void 0;return{docElement:(0,o.v)(s),sidebarName:l,sidebarItems:c}}},1003:(e,t,n)=>{"use strict";n.d(t,{e3:()=>f,be:()=>u,Jx:()=>p});var a=n(6540),r=n(53),o=n(5260),s=n(3102);function i(){const e=a.useContext(s.o);if(!e)throw new Error("Unexpected: no Docusaurus route context found");return e}var l=n(6025),c=n(4586);function u(e){let{title:t,description:n,keywords:r,image:s,children:i}=e;const u=function(e){const{siteConfig:t}=(0,c.A)(),{title:n,titleDelimiter:a}=t;return e?.trim().length?`${e.trim()} ${a} ${n}`:n}(t),{withBaseUrl:d}=(0,l.h)(),f=s?d(s,{absolute:!0}):void 0;return a.createElement(o.A,null,t&&a.createElement("title",null,u),t&&a.createElement("meta",{property:"og:title",content:u}),n&&a.createElement("meta",{name:"description",content:n}),n&&a.createElement("meta",{property:"og:description",content:n}),r&&a.createElement("meta",{name:"keywords",content:Array.isArray(r)?r.join(","):r}),f&&a.createElement("meta",{property:"og:image",content:f}),f&&a.createElement("meta",{name:"twitter:image",content:f}),i)}const d=a.createContext(void 0);function f(e){let{className:t,children:n}=e;const s=a.useContext(d),i=(0,r.A)(s,t);return a.createElement(d.Provider,{value:i},a.createElement(o.A,null,a.createElement("html",{className:i})),n)}function p(e){let{children:t}=e;const n=i(),o=`plugin-${n.plugin.name.replace(/docusaurus-(?:plugin|theme)-(?:content-)?/gi,"")}`;const s=`plugin-id-${n.plugin.id}`;return a.createElement(f,{className:(0,r.A)(o,s)},t)}},9532:(e,t,n)=>{"use strict";n.d(t,{Be:()=>l,ZC:()=>s,_q:()=>o,dV:()=>i,fM:()=>c});var a=n(6540);const r=n(8193).A.canUseDOM?a.useLayoutEffect:a.useEffect;function o(e){const t=(0,a.useRef)(e);return r((()=>{t.current=e}),[e]),(0,a.useCallback)((function(){return t.current(...arguments)}),[])}function s(e){const t=(0,a.useRef)();return r((()=>{t.current=e})),t.current}class i extends Error{constructor(e,t){super(),this.name="ReactContextError",this.message=`Hook ${this.stack?.split("\n")[1]?.match(/at (?:\w+\.)?(?<name>\w+)/)?.groups.name??""} is called outside the <${e}>. ${t??""}`}}function l(e){const t=Object.entries(e);return t.sort(((e,t)=>e[0].localeCompare(t[0]))),(0,a.useMemo)((()=>e),t.flat())}function c(e){return t=>{let{children:n}=t;return a.createElement(a.Fragment,null,e.reduceRight(((e,t)=>a.createElement(t,null,e)),n))}}},9169:(e,t,n)=>{"use strict";n.d(t,{Dt:()=>i,ys:()=>s});var a=n(6540),r=n(8328),o=n(4586);function s(e,t){const n=e=>(!e||e.endsWith("/")?e:`${e}/`)?.toLowerCase();return n(e)===n(t)}function i(){const{baseUrl:e}=(0,o.A)().siteConfig;return(0,a.useMemo)((()=>function(e){let{baseUrl:t,routes:n}=e;function a(e){return e.path===t&&!0===e.exact}function r(e){return e.path===t&&!e.exact}return function e(t){if(0===t.length)return;return t.find(a)||e(t.filter(r).flatMap((e=>e.routes??[])))}(n)}({routes:r.A,baseUrl:e})),[e])}},3104:(e,t,n)=>{"use strict";n.d(t,{Mq:()=>d,Tv:()=>l,gk:()=>f});var a=n(6540),r=n(8193),o=n(2303),s=n(9532);const i=a.createContext(void 0);function l(e){let{children:t}=e;const n=function(){const e=(0,a.useRef)(!0);return(0,a.useMemo)((()=>({scrollEventsEnabledRef:e,enableScrollEvents:()=>{e.current=!0},disableScrollEvents:()=>{e.current=!1}})),[])}();return a.createElement(i.Provider,{value:n},t)}function c(){const e=(0,a.useContext)(i);if(null==e)throw new s.dV("ScrollControllerProvider");return e}const u=()=>r.A.canUseDOM?{scrollX:window.pageXOffset,scrollY:window.pageYOffset}:null;function d(e,t){void 0===t&&(t=[]);const{scrollEventsEnabledRef:n}=c(),r=(0,a.useRef)(u()),o=(0,s._q)(e);(0,a.useEffect)((()=>{const e=()=>{if(!n.current)return;const e=u();o(e,r.current),r.current=e},t={passive:!0};return e(),window.addEventListener("scroll",e,t),()=>window.removeEventListener("scroll",e,t)}),[o,n,...t])}function f(){const e=(0,a.useRef)(null),t=(0,o.A)()&&"smooth"===getComputedStyle(document.documentElement).scrollBehavior;return{startScroll:n=>{e.current=t?function(e){return window.scrollTo({top:e,behavior:"smooth"}),()=>{}}(n):function(e){let t=null;const n=document.documentElement.scrollTop>e;return function a(){const r=document.documentElement.scrollTop;(n&&r>e||!n&&r<e)&&(t=requestAnimationFrame(a),window.scrollTo(0,Math.floor(.85*(r-e))+e))}(),()=>t&&cancelAnimationFrame(t)}(n)},cancelScroll:()=>e.current?.()}}},2967:(e,t,n)=>{"use strict";n.d(t,{Cy:()=>a,tU:()=>r});n(4586);const a="default";function r(e,t){return`docs-${e}-${t}`}},9466:(e,t,n)=>{"use strict";n.d(t,{Wf:()=>l});n(6540),n(9888);const a="localStorage";function r(e){let{key:t,oldValue:n,newValue:a,storage:r}=e;if(n===a)return;const o=document.createEvent("StorageEvent");o.initStorageEvent("storage",!1,!1,t,n,a,window.location.href,r),window.dispatchEvent(o)}function o(e){if(void 0===e&&(e=a),"undefined"==typeof window)throw new Error("Browser storage is not available on Node.js/Docusaurus SSR process.");if("none"===e)return null;try{return window[e]}catch(n){return t=n,s||(console.warn("Docusaurus browser storage is not available.\nPossible reasons: running Docusaurus in an iframe, in an incognito browser session, or using too strict browser privacy settings.",t),s=!0),null}var t}let s=!1;const i={get:()=>null,set:()=>{},del:()=>{},listen:()=>()=>{}};function l(e,t){if("undefined"==typeof window)return function(e){function t(){throw new Error(`Illegal storage API usage for storage key "${e}".\nDocusaurus storage APIs are not supposed to be called on the server-rendering process.\nPlease only call storage APIs in effects and event handlers.`)}return{get:t,set:t,del:t,listen:t}}(e);const n=o(t?.persistence);return null===n?i:{get:()=>{try{return n.getItem(e)}catch(t){return console.error(`Docusaurus storage error, can't get key=${e}`,t),null}},set:t=>{try{const a=n.getItem(e);n.setItem(e,t),r({key:e,oldValue:a,newValue:t,storage:n})}catch(a){console.error(`Docusaurus storage error, can't set ${e}=${t}`,a)}},del:()=>{try{const t=n.getItem(e);n.removeItem(e),r({key:e,oldValue:t,newValue:null,storage:n})}catch(t){console.error(`Docusaurus storage error, can't delete key=${e}`,t)}},listen:t=>{try{const a=a=>{a.storageArea===n&&a.key===e&&t(a)};return window.addEventListener("storage",a),()=>window.removeEventListener("storage",a)}catch(a){return console.error(`Docusaurus storage error, can't listen for changes of key=${e}`,a),()=>{}}}}}},2131:(e,t,n)=>{"use strict";n.d(t,{o:()=>s});var a=n(4586),r=n(6347),o=n(440);function s(){const{siteConfig:{baseUrl:e,url:t,trailingSlash:n},i18n:{defaultLocale:s,currentLocale:i}}=(0,a.A)(),{pathname:l}=(0,r.zy)(),c=(0,o.applyTrailingSlash)(l,{trailingSlash:n,baseUrl:e}),u=i===s?e:e.replace(`/${i}/`,"/"),d=c.replace(e,"");return{createUrl:function(e){let{locale:n,fullyQualified:a}=e;return`${a?t:""}${function(e){return e===s?`${u}`:`${u}${e}/`}(n)}${d}`}}}},5062:(e,t,n)=>{"use strict";n.d(t,{$:()=>s});var a=n(6540),r=n(6347),o=n(9532);function s(e){const t=(0,r.zy)(),n=(0,o.ZC)(t),s=(0,o._q)(e);(0,a.useEffect)((()=>{n&&t!==n&&s({location:t,previousLocation:n})}),[s,t,n])}},6342:(e,t,n)=>{"use strict";n.d(t,{p:()=>r});var a=n(4586);function r(){return(0,a.A)().siteConfig.themeConfig}},2983:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e,t){const{trailingSlash:n,baseUrl:a}=t;if(e.startsWith("#"))return e;if(void 0===n)return e;const[r]=e.split(/[#?]/),o="/"===r||r===a?r:(s=r,n?function(e){return e.endsWith("/")?e:`${e}/`}(s):function(e){return e.endsWith("/")?e.slice(0,-1):e}(s));var s;return e.replace(r,o)}},253:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.getErrorCausalChain=void 0,t.getErrorCausalChain=function e(t){return t.cause?[t,...e(t.cause)]:[t]}},440:function(e,t,n){"use strict";var a=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.getErrorCausalChain=t.applyTrailingSlash=t.blogPostContainerID=void 0,t.blogPostContainerID="__blog-post-container";var r=n(2983);Object.defineProperty(t,"applyTrailingSlash",{enumerable:!0,get:function(){return a(r).default}});var o=n(253);Object.defineProperty(t,"getErrorCausalChain",{enumerable:!0,get:function(){return o.getErrorCausalChain}})},53:(e,t,n)=>{"use strict";function a(e){var t,n,r="";if("string"==typeof e||"number"==typeof e)r+=e;else if("object"==typeof e)if(Array.isArray(e))for(t=0;t<e.length;t++)e[t]&&(n=a(e[t]))&&(r&&(r+=" "),r+=n);else for(t in e)e[t]&&(r&&(r+=" "),r+=t);return r}n.d(t,{A:()=>r});const r=function(){for(var e,t,n=0,r="";n<arguments.length;)(e=arguments[n++])&&(t=a(e))&&(r&&(r+=" "),r+=t);return r}},1513:(e,t,n)=>{"use strict";n.d(t,{zR:()=>x,TM:()=>A,yJ:()=>p,sC:()=>q,AO:()=>f});var a=n(8168);function r(e){return"/"===e.charAt(0)}function o(e,t){for(var n=t,a=n+1,r=e.length;a<r;n+=1,a+=1)e[n]=e[a];e.pop()}const s=function(e,t){void 0===t&&(t="");var n,a=e&&e.split("/")||[],s=t&&t.split("/")||[],i=e&&r(e),l=t&&r(t),c=i||l;if(e&&r(e)?s=a:a.length&&(s.pop(),s=s.concat(a)),!s.length)return"/";if(s.length){var u=s[s.length-1];n="."===u||".."===u||""===u}else n=!1;for(var d=0,f=s.length;f>=0;f--){var p=s[f];"."===p?o(s,f):".."===p?(o(s,f),d++):d&&(o(s,f),d--)}if(!c)for(;d--;d)s.unshift("..");!c||""===s[0]||s[0]&&r(s[0])||s.unshift("");var m=s.join("/");return n&&"/"!==m.substr(-1)&&(m+="/"),m};var i=n(1561);function l(e){return"/"===e.charAt(0)?e:"/"+e}function c(e){return"/"===e.charAt(0)?e.substr(1):e}function u(e,t){return function(e,t){return 0===e.toLowerCase().indexOf(t.toLowerCase())&&-1!=="/?#".indexOf(e.charAt(t.length))}(e,t)?e.substr(t.length):e}function d(e){return"/"===e.charAt(e.length-1)?e.slice(0,-1):e}function f(e){var t=e.pathname,n=e.search,a=e.hash,r=t||"/";return n&&"?"!==n&&(r+="?"===n.charAt(0)?n:"?"+n),a&&"#"!==a&&(r+="#"===a.charAt(0)?a:"#"+a),r}function p(e,t,n,r){var o;"string"==typeof e?(o=function(e){var t=e||"/",n="",a="",r=t.indexOf("#");-1!==r&&(a=t.substr(r),t=t.substr(0,r));var o=t.indexOf("?");return-1!==o&&(n=t.substr(o),t=t.substr(0,o)),{pathname:t,search:"?"===n?"":n,hash:"#"===a?"":a}}(e),o.state=t):(void 0===(o=(0,a.A)({},e)).pathname&&(o.pathname=""),o.search?"?"!==o.search.charAt(0)&&(o.search="?"+o.search):o.search="",o.hash?"#"!==o.hash.charAt(0)&&(o.hash="#"+o.hash):o.hash="",void 0!==t&&void 0===o.state&&(o.state=t));try{o.pathname=decodeURI(o.pathname)}catch(i){throw i instanceof URIError?new URIError('Pathname "'+o.pathname+'" could not be decoded. This is likely caused by an invalid percent-encoding.'):i}return n&&(o.key=n),r?o.pathname?"/"!==o.pathname.charAt(0)&&(o.pathname=s(o.pathname,r.pathname)):o.pathname=r.pathname:o.pathname||(o.pathname="/"),o}function m(){var e=null;var t=[];return{setPrompt:function(t){return e=t,function(){e===t&&(e=null)}},confirmTransitionTo:function(t,n,a,r){if(null!=e){var o="function"==typeof e?e(t,n):e;"string"==typeof o?"function"==typeof a?a(o,r):r(!0):r(!1!==o)}else r(!0)},appendListener:function(e){var n=!0;function a(){n&&e.apply(void 0,arguments)}return t.push(a),function(){n=!1,t=t.filter((function(e){return e!==a}))}},notifyListeners:function(){for(var e=arguments.length,n=new Array(e),a=0;a<e;a++)n[a]=arguments[a];t.forEach((function(e){return e.apply(void 0,n)}))}}}var g=!("undefined"==typeof window||!window.document||!window.document.createElement);function h(e,t){t(window.confirm(e))}var b="popstate",y="hashchange";function v(){try{return window.history.state||{}}catch(e){return{}}}function x(e){void 0===e&&(e={}),g||(0,i.A)(!1);var t,n=window.history,r=(-1===(t=window.navigator.userAgent).indexOf("Android 2.")&&-1===t.indexOf("Android 4.0")||-1===t.indexOf("Mobile Safari")||-1!==t.indexOf("Chrome")||-1!==t.indexOf("Windows Phone"))&&window.history&&"pushState"in window.history,o=!(-1===window.navigator.userAgent.indexOf("Trident")),s=e,c=s.forceRefresh,x=void 0!==c&&c,w=s.getUserConfirmation,S=void 0===w?h:w,E=s.keyLength,k=void 0===E?6:E,_=e.basename?d(l(e.basename)):"";function A(e){var t=e||{},n=t.key,a=t.state,r=window.location,o=r.pathname+r.search+r.hash;return _&&(o=u(o,_)),p(o,a,n)}function C(){return Math.random().toString(36).substr(2,k)}var q=m();function T(e){(0,a.A)(z,e),z.length=n.length,q.notifyListeners(z.location,z.action)}function N(e){(function(e){return void 0===e.state&&-1===navigator.userAgent.indexOf("CriOS")})(e)||P(A(e.state))}function L(){P(A(v()))}var O=!1;function P(e){if(O)O=!1,T();else{q.confirmTransitionTo(e,"POP",S,(function(t){t?T({action:"POP",location:e}):function(e){var t=z.location,n=I.indexOf(t.key);-1===n&&(n=0);var a=I.indexOf(e.key);-1===a&&(a=0);var r=n-a;r&&(O=!0,D(r))}(e)}))}}var R=A(v()),I=[R.key];function M(e){return _+f(e)}function D(e){n.go(e)}var F=0;function B(e){1===(F+=e)&&1===e?(window.addEventListener(b,N),o&&window.addEventListener(y,L)):0===F&&(window.removeEventListener(b,N),o&&window.removeEventListener(y,L))}var j=!1;var z={length:n.length,action:"POP",location:R,createHref:M,push:function(e,t){var a="PUSH",o=p(e,t,C(),z.location);q.confirmTransitionTo(o,a,S,(function(e){if(e){var t=M(o),s=o.key,i=o.state;if(r)if(n.pushState({key:s,state:i},null,t),x)window.location.href=t;else{var l=I.indexOf(z.location.key),c=I.slice(0,l+1);c.push(o.key),I=c,T({action:a,location:o})}else window.location.href=t}}))},replace:function(e,t){var a="REPLACE",o=p(e,t,C(),z.location);q.confirmTransitionTo(o,a,S,(function(e){if(e){var t=M(o),s=o.key,i=o.state;if(r)if(n.replaceState({key:s,state:i},null,t),x)window.location.replace(t);else{var l=I.indexOf(z.location.key);-1!==l&&(I[l]=o.key),T({action:a,location:o})}else window.location.replace(t)}}))},go:D,goBack:function(){D(-1)},goForward:function(){D(1)},block:function(e){void 0===e&&(e=!1);var t=q.setPrompt(e);return j||(B(1),j=!0),function(){return j&&(j=!1,B(-1)),t()}},listen:function(e){var t=q.appendListener(e);return B(1),function(){B(-1),t()}}};return z}var w="hashchange",S={hashbang:{encodePath:function(e){return"!"===e.charAt(0)?e:"!/"+c(e)},decodePath:function(e){return"!"===e.charAt(0)?e.substr(1):e}},noslash:{encodePath:c,decodePath:l},slash:{encodePath:l,decodePath:l}};function E(e){var t=e.indexOf("#");return-1===t?e:e.slice(0,t)}function k(){var e=window.location.href,t=e.indexOf("#");return-1===t?"":e.substring(t+1)}function _(e){window.location.replace(E(window.location.href)+"#"+e)}function A(e){void 0===e&&(e={}),g||(0,i.A)(!1);var t=window.history,n=(window.navigator.userAgent.indexOf("Firefox"),e),r=n.getUserConfirmation,o=void 0===r?h:r,s=n.hashType,c=void 0===s?"slash":s,b=e.basename?d(l(e.basename)):"",y=S[c],v=y.encodePath,x=y.decodePath;function A(){var e=x(k());return b&&(e=u(e,b)),p(e)}var C=m();function q(e){(0,a.A)(j,e),j.length=t.length,C.notifyListeners(j.location,j.action)}var T=!1,N=null;function L(){var e,t,n=k(),a=v(n);if(n!==a)_(a);else{var r=A(),s=j.location;if(!T&&(t=r,(e=s).pathname===t.pathname&&e.search===t.search&&e.hash===t.hash))return;if(N===f(r))return;N=null,function(e){if(T)T=!1,q();else{var t="POP";C.confirmTransitionTo(e,t,o,(function(n){n?q({action:t,location:e}):function(e){var t=j.location,n=I.lastIndexOf(f(t));-1===n&&(n=0);var a=I.lastIndexOf(f(e));-1===a&&(a=0);var r=n-a;r&&(T=!0,M(r))}(e)}))}}(r)}}var O=k(),P=v(O);O!==P&&_(P);var R=A(),I=[f(R)];function M(e){t.go(e)}var D=0;function F(e){1===(D+=e)&&1===e?window.addEventListener(w,L):0===D&&window.removeEventListener(w,L)}var B=!1;var j={length:t.length,action:"POP",location:R,createHref:function(e){var t=document.querySelector("base"),n="";return t&&t.getAttribute("href")&&(n=E(window.location.href)),n+"#"+v(b+f(e))},push:function(e,t){var n="PUSH",a=p(e,void 0,void 0,j.location);C.confirmTransitionTo(a,n,o,(function(e){if(e){var t=f(a),r=v(b+t);if(k()!==r){N=t,function(e){window.location.hash=e}(r);var o=I.lastIndexOf(f(j.location)),s=I.slice(0,o+1);s.push(t),I=s,q({action:n,location:a})}else q()}}))},replace:function(e,t){var n="REPLACE",a=p(e,void 0,void 0,j.location);C.confirmTransitionTo(a,n,o,(function(e){if(e){var t=f(a),r=v(b+t);k()!==r&&(N=t,_(r));var o=I.indexOf(f(j.location));-1!==o&&(I[o]=t),q({action:n,location:a})}}))},go:M,goBack:function(){M(-1)},goForward:function(){M(1)},block:function(e){void 0===e&&(e=!1);var t=C.setPrompt(e);return B||(F(1),B=!0),function(){return B&&(B=!1,F(-1)),t()}},listen:function(e){var t=C.appendListener(e);return F(1),function(){F(-1),t()}}};return j}function C(e,t,n){return Math.min(Math.max(e,t),n)}function q(e){void 0===e&&(e={});var t=e,n=t.getUserConfirmation,r=t.initialEntries,o=void 0===r?["/"]:r,s=t.initialIndex,i=void 0===s?0:s,l=t.keyLength,c=void 0===l?6:l,u=m();function d(e){(0,a.A)(x,e),x.length=x.entries.length,u.notifyListeners(x.location,x.action)}function g(){return Math.random().toString(36).substr(2,c)}var h=C(i,0,o.length-1),b=o.map((function(e){return p(e,void 0,"string"==typeof e?g():e.key||g())})),y=f;function v(e){var t=C(x.index+e,0,x.entries.length-1),a=x.entries[t];u.confirmTransitionTo(a,"POP",n,(function(e){e?d({action:"POP",location:a,index:t}):d()}))}var x={length:b.length,action:"POP",location:b[h],index:h,entries:b,createHref:y,push:function(e,t){var a="PUSH",r=p(e,t,g(),x.location);u.confirmTransitionTo(r,a,n,(function(e){if(e){var t=x.index+1,n=x.entries.slice(0);n.length>t?n.splice(t,n.length-t,r):n.push(r),d({action:a,location:r,index:t,entries:n})}}))},replace:function(e,t){var a="REPLACE",r=p(e,t,g(),x.location);u.confirmTransitionTo(r,a,n,(function(e){e&&(x.entries[x.index]=r,d({action:a,location:r}))}))},go:v,goBack:function(){v(-1)},goForward:function(){v(1)},canGo:function(e){var t=x.index+e;return t>=0&&t<x.entries.length},block:function(e){return void 0===e&&(e=!1),u.setPrompt(e)},listen:function(e){return u.appendListener(e)}};return x}},4146:(e,t,n)=>{"use strict";var a=n(4363),r={childContextTypes:!0,contextType:!0,contextTypes:!0,defaultProps:!0,displayName:!0,getDefaultProps:!0,getDerivedStateFromError:!0,getDerivedStateFromProps:!0,mixins:!0,propTypes:!0,type:!0},o={name:!0,length:!0,prototype:!0,caller:!0,callee:!0,arguments:!0,arity:!0},s={$$typeof:!0,compare:!0,defaultProps:!0,displayName:!0,propTypes:!0,type:!0},i={};function l(e){return a.isMemo(e)?s:i[e.$$typeof]||r}i[a.ForwardRef]={$$typeof:!0,render:!0,defaultProps:!0,displayName:!0,propTypes:!0},i[a.Memo]=s;var c=Object.defineProperty,u=Object.getOwnPropertyNames,d=Object.getOwnPropertySymbols,f=Object.getOwnPropertyDescriptor,p=Object.getPrototypeOf,m=Object.prototype;e.exports=function e(t,n,a){if("string"!=typeof n){if(m){var r=p(n);r&&r!==m&&e(t,r,a)}var s=u(n);d&&(s=s.concat(d(n)));for(var i=l(t),g=l(n),h=0;h<s.length;++h){var b=s[h];if(!(o[b]||a&&a[b]||g&&g[b]||i&&i[b])){var y=f(n,b);try{c(t,b,y)}catch(v){}}}}return t}},311:e=>{"use strict";e.exports=function(e,t,n,a,r,o,s,i){if(!e){var l;if(void 0===t)l=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var c=[n,a,r,o,s,i],u=0;(l=new Error(t.replace(/%s/g,(function(){return c[u++]})))).name="Invariant Violation"}throw l.framesToPop=1,l}}},4634:e=>{e.exports=Array.isArray||function(e){return"[object Array]"==Object.prototype.toString.call(e)}},119:(e,t,n)=>{"use strict";n.r(t)},1043:(e,t,n)=>{"use strict";n.r(t)},5947:function(e,t,n){var a,r;a=function(){var e,t,n={version:"0.2.0"},a=n.settings={minimum:.08,easing:"ease",positionUsing:"",speed:200,trickle:!0,trickleRate:.02,trickleSpeed:800,showSpinner:!0,barSelector:'[role="bar"]',spinnerSelector:'[role="spinner"]',parent:"body",template:'<div class="bar" role="bar"><div class="peg"></div></div><div class="spinner" role="spinner"><div class="spinner-icon"></div></div>'};function r(e,t,n){return e<t?t:e>n?n:e}function o(e){return 100*(-1+e)}function s(e,t,n){var r;return(r="translate3d"===a.positionUsing?{transform:"translate3d("+o(e)+"%,0,0)"}:"translate"===a.positionUsing?{transform:"translate("+o(e)+"%,0)"}:{"margin-left":o(e)+"%"}).transition="all "+t+"ms "+n,r}n.configure=function(e){var t,n;for(t in e)void 0!==(n=e[t])&&e.hasOwnProperty(t)&&(a[t]=n);return this},n.status=null,n.set=function(e){var t=n.isStarted();e=r(e,a.minimum,1),n.status=1===e?null:e;var o=n.render(!t),c=o.querySelector(a.barSelector),u=a.speed,d=a.easing;return o.offsetWidth,i((function(t){""===a.positionUsing&&(a.positionUsing=n.getPositioningCSS()),l(c,s(e,u,d)),1===e?(l(o,{transition:"none",opacity:1}),o.offsetWidth,setTimeout((function(){l(o,{transition:"all "+u+"ms linear",opacity:0}),setTimeout((function(){n.remove(),t()}),u)}),u)):setTimeout(t,u)})),this},n.isStarted=function(){return"number"==typeof n.status},n.start=function(){n.status||n.set(0);var e=function(){setTimeout((function(){n.status&&(n.trickle(),e())}),a.trickleSpeed)};return a.trickle&&e(),this},n.done=function(e){return e||n.status?n.inc(.3+.5*Math.random()).set(1):this},n.inc=function(e){var t=n.status;return t?("number"!=typeof e&&(e=(1-t)*r(Math.random()*t,.1,.95)),t=r(t+e,0,.994),n.set(t)):n.start()},n.trickle=function(){return n.inc(Math.random()*a.trickleRate)},e=0,t=0,n.promise=function(a){return a&&"resolved"!==a.state()?(0===t&&n.start(),e++,t++,a.always((function(){0==--t?(e=0,n.done()):n.set((e-t)/e)})),this):this},n.render=function(e){if(n.isRendered())return document.getElementById("nprogress");u(document.documentElement,"nprogress-busy");var t=document.createElement("div");t.id="nprogress",t.innerHTML=a.template;var r,s=t.querySelector(a.barSelector),i=e?"-100":o(n.status||0),c=document.querySelector(a.parent);return l(s,{transition:"all 0 linear",transform:"translate3d("+i+"%,0,0)"}),a.showSpinner||(r=t.querySelector(a.spinnerSelector))&&p(r),c!=document.body&&u(c,"nprogress-custom-parent"),c.appendChild(t),t},n.remove=function(){d(document.documentElement,"nprogress-busy"),d(document.querySelector(a.parent),"nprogress-custom-parent");var e=document.getElementById("nprogress");e&&p(e)},n.isRendered=function(){return!!document.getElementById("nprogress")},n.getPositioningCSS=function(){var e=document.body.style,t="WebkitTransform"in e?"Webkit":"MozTransform"in e?"Moz":"msTransform"in e?"ms":"OTransform"in e?"O":"";return t+"Perspective"in e?"translate3d":t+"Transform"in e?"translate":"margin"};var i=function(){var e=[];function t(){var n=e.shift();n&&n(t)}return function(n){e.push(n),1==e.length&&t()}}(),l=function(){var e=["Webkit","O","Moz","ms"],t={};function n(e){return e.replace(/^-ms-/,"ms-").replace(/-([\da-z])/gi,(function(e,t){return t.toUpperCase()}))}function a(t){var n=document.body.style;if(t in n)return t;for(var a,r=e.length,o=t.charAt(0).toUpperCase()+t.slice(1);r--;)if((a=e[r]+o)in n)return a;return t}function r(e){return e=n(e),t[e]||(t[e]=a(e))}function o(e,t,n){t=r(t),e.style[t]=n}return function(e,t){var n,a,r=arguments;if(2==r.length)for(n in t)void 0!==(a=t[n])&&t.hasOwnProperty(n)&&o(e,n,a);else o(e,r[1],r[2])}}();function c(e,t){return("string"==typeof e?e:f(e)).indexOf(" "+t+" ")>=0}function u(e,t){var n=f(e),a=n+t;c(n,t)||(e.className=a.substring(1))}function d(e,t){var n,a=f(e);c(e,t)&&(n=a.replace(" "+t+" "," "),e.className=n.substring(1,n.length-1))}function f(e){return(" "+(e.className||"")+" ").replace(/\s+/gi," ")}function p(e){e&&e.parentNode&&e.parentNode.removeChild(e)}return n},void 0===(r="function"==typeof a?a.call(t,n,t,e):a)||(e.exports=r)},5228:e=>{"use strict";var t=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,a=Object.prototype.propertyIsEnumerable;e.exports=function(){try{if(!Object.assign)return!1;var e=new String("abc");if(e[5]="de","5"===Object.getOwnPropertyNames(e)[0])return!1;for(var t={},n=0;n<10;n++)t["_"+String.fromCharCode(n)]=n;if("0123456789"!==Object.getOwnPropertyNames(t).map((function(e){return t[e]})).join(""))return!1;var a={};return"abcdefghijklmnopqrst".split("").forEach((function(e){a[e]=e})),"abcdefghijklmnopqrst"===Object.keys(Object.assign({},a)).join("")}catch(r){return!1}}()?Object.assign:function(e,r){for(var o,s,i=function(e){if(null==e)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(e)}(e),l=1;l<arguments.length;l++){for(var c in o=Object(arguments[l]))n.call(o,c)&&(i[c]=o[c]);if(t){s=t(o);for(var u=0;u<s.length;u++)a.call(o,s[u])&&(i[s[u]]=o[s[u]])}}return i}},1258:(e,t,n)=>{"use strict";n.d(t,{A:()=>o});var a=function(){var e=/(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i,t=0,n={},a={util:{encode:function e(t){return t instanceof r?new r(t.type,e(t.content),t.alias):Array.isArray(t)?t.map(e):t.replace(/&/g,"&").replace(/</g,"<").replace(/\u00a0/g," ")},type:function(e){return Object.prototype.toString.call(e).slice(8,-1)},objId:function(e){return e.__id||Object.defineProperty(e,"__id",{value:++t}),e.__id},clone:function e(t,n){var r,o;switch(n=n||{},a.util.type(t)){case"Object":if(o=a.util.objId(t),n[o])return n[o];for(var s in r={},n[o]=r,t)t.hasOwnProperty(s)&&(r[s]=e(t[s],n));return r;case"Array":return o=a.util.objId(t),n[o]?n[o]:(r=[],n[o]=r,t.forEach((function(t,a){r[a]=e(t,n)})),r);default:return t}},getLanguage:function(t){for(;t;){var n=e.exec(t.className);if(n)return n[1].toLowerCase();t=t.parentElement}return"none"},setLanguage:function(t,n){t.className=t.className.replace(RegExp(e,"gi"),""),t.classList.add("language-"+n)},isActive:function(e,t,n){for(var a="no-"+t;e;){var r=e.classList;if(r.contains(t))return!0;if(r.contains(a))return!1;e=e.parentElement}return!!n}},languages:{plain:n,plaintext:n,text:n,txt:n,extend:function(e,t){var n=a.util.clone(a.languages[e]);for(var r in t)n[r]=t[r];return n},insertBefore:function(e,t,n,r){var o=(r=r||a.languages)[e],s={};for(var i in o)if(o.hasOwnProperty(i)){if(i==t)for(var l in n)n.hasOwnProperty(l)&&(s[l]=n[l]);n.hasOwnProperty(i)||(s[i]=o[i])}var c=r[e];return r[e]=s,a.languages.DFS(a.languages,(function(t,n){n===c&&t!=e&&(this[t]=s)})),s},DFS:function e(t,n,r,o){o=o||{};var s=a.util.objId;for(var i in t)if(t.hasOwnProperty(i)){n.call(t,i,t[i],r||i);var l=t[i],c=a.util.type(l);"Object"!==c||o[s(l)]?"Array"!==c||o[s(l)]||(o[s(l)]=!0,e(l,n,i,o)):(o[s(l)]=!0,e(l,n,null,o))}}},plugins:{},highlight:function(e,t,n){var o={code:e,grammar:t,language:n};return a.hooks.run("before-tokenize",o),o.tokens=a.tokenize(o.code,o.grammar),a.hooks.run("after-tokenize",o),r.stringify(a.util.encode(o.tokens),o.language)},tokenize:function(e,t){var n=t.rest;if(n){for(var a in n)t[a]=n[a];delete t.rest}var r=new i;return l(r,r.head,e),s(e,r,t,r.head,0),function(e){var t=[],n=e.head.next;for(;n!==e.tail;)t.push(n.value),n=n.next;return t}(r)},hooks:{all:{},add:function(e,t){var n=a.hooks.all;n[e]=n[e]||[],n[e].push(t)},run:function(e,t){var n=a.hooks.all[e];if(n&&n.length)for(var r,o=0;r=n[o++];)r(t)}},Token:r};function r(e,t,n,a){this.type=e,this.content=t,this.alias=n,this.length=0|(a||"").length}function o(e,t,n,a){e.lastIndex=t;var r=e.exec(n);if(r&&a&&r[1]){var o=r[1].length;r.index+=o,r[0]=r[0].slice(o)}return r}function s(e,t,n,i,u,d){for(var f in n)if(n.hasOwnProperty(f)&&n[f]){var p=n[f];p=Array.isArray(p)?p:[p];for(var m=0;m<p.length;++m){if(d&&d.cause==f+","+m)return;var g=p[m],h=g.inside,b=!!g.lookbehind,y=!!g.greedy,v=g.alias;if(y&&!g.pattern.global){var x=g.pattern.toString().match(/[imsuy]*$/)[0];g.pattern=RegExp(g.pattern.source,x+"g")}for(var w=g.pattern||g,S=i.next,E=u;S!==t.tail&&!(d&&E>=d.reach);E+=S.value.length,S=S.next){var k=S.value;if(t.length>e.length)return;if(!(k instanceof r)){var _,A=1;if(y){if(!(_=o(w,E,e,b))||_.index>=e.length)break;var C=_.index,q=_.index+_[0].length,T=E;for(T+=S.value.length;C>=T;)T+=(S=S.next).value.length;if(E=T-=S.value.length,S.value instanceof r)continue;for(var N=S;N!==t.tail&&(T<q||"string"==typeof N.value);N=N.next)A++,T+=N.value.length;A--,k=e.slice(E,T),_.index-=E}else if(!(_=o(w,0,k,b)))continue;C=_.index;var L=_[0],O=k.slice(0,C),P=k.slice(C+L.length),R=E+k.length;d&&R>d.reach&&(d.reach=R);var I=S.prev;if(O&&(I=l(t,I,O),E+=O.length),c(t,I,A),S=l(t,I,new r(f,h?a.tokenize(L,h):L,v,L)),P&&l(t,S,P),A>1){var M={cause:f+","+m,reach:R};s(e,t,n,S.prev,E,M),d&&M.reach>d.reach&&(d.reach=M.reach)}}}}}}function i(){var e={value:null,prev:null,next:null},t={value:null,prev:e,next:null};e.next=t,this.head=e,this.tail=t,this.length=0}function l(e,t,n){var a=t.next,r={value:n,prev:t,next:a};return t.next=r,a.prev=r,e.length++,r}function c(e,t,n){for(var a=t.next,r=0;r<n&&a!==e.tail;r++)a=a.next;t.next=a,a.prev=t,e.length-=r}return r.stringify=function e(t,n){if("string"==typeof t)return t;if(Array.isArray(t)){var r="";return t.forEach((function(t){r+=e(t,n)})),r}var o={type:t.type,content:e(t.content,n),tag:"span",classes:["token",t.type],attributes:{},language:n},s=t.alias;s&&(Array.isArray(s)?Array.prototype.push.apply(o.classes,s):o.classes.push(s)),a.hooks.run("wrap",o);var i="";for(var l in o.attributes)i+=" "+l+'="'+(o.attributes[l]||"").replace(/"/g,""")+'"';return"<"+o.tag+' class="'+o.classes.join(" ")+'"'+i+">"+o.content+"</"+o.tag+">"},a}(),r=a;a.default=a,r.languages.markup={comment:{pattern:/<!--(?:(?!<!--)[\s\S])*?-->/,greedy:!0},prolog:{pattern:/<\?[\s\S]+?\?>/,greedy:!0},doctype:{pattern:/<!DOCTYPE(?:[^>"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|<!--(?:[^-]|-(?!->))*-->)*\]\s*)?>/i,greedy:!0,inside:{"internal-subset":{pattern:/(^[^\[]*\[)[\s\S]+(?=\]>$)/,lookbehind:!0,greedy:!0,inside:null},string:{pattern:/"[^"]*"|'[^']*'/,greedy:!0},punctuation:/^<!|>$|[[\]]/,"doctype-tag":/^DOCTYPE/i,name:/[^\s<>'"]+/}},cdata:{pattern:/<!\[CDATA\[[\s\S]*?\]\]>/i,greedy:!0},tag:{pattern:/<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/,greedy:!0,inside:{tag:{pattern:/^<\/?[^\s>\/]+/,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"special-attr":[],"attr-value":{pattern:/=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,inside:{punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:[{pattern:/&[\da-z]{1,8};/i,alias:"named-entity"},/&#x?[\da-f]{1,8};/i]},r.languages.markup.tag.inside["attr-value"].inside.entity=r.languages.markup.entity,r.languages.markup.doctype.inside["internal-subset"].inside=r.languages.markup,r.hooks.add("wrap",(function(e){"entity"===e.type&&(e.attributes.title=e.content.replace(/&/,"&"))})),Object.defineProperty(r.languages.markup.tag,"addInlined",{value:function(e,t){var n={};n["language-"+t]={pattern:/(^<!\[CDATA\[)[\s\S]+?(?=\]\]>$)/i,lookbehind:!0,inside:r.languages[t]},n.cdata=/^<!\[CDATA\[|\]\]>$/i;var a={"included-cdata":{pattern:/<!\[CDATA\[[\s\S]*?\]\]>/i,inside:n}};a["language-"+t]={pattern:/[\s\S]+/,inside:r.languages[t]};var o={};o[e]={pattern:RegExp(/(<__[^>]*>)(?:<!\[CDATA\[(?:[^\]]|\](?!\]>))*\]\]>|(?!<!\[CDATA\[)[\s\S])*?(?=<\/__>)/.source.replace(/__/g,(function(){return e})),"i"),lookbehind:!0,greedy:!0,inside:a},r.languages.insertBefore("markup","cdata",o)}}),Object.defineProperty(r.languages.markup.tag,"addAttribute",{value:function(e,t){r.languages.markup.tag.inside["special-attr"].push({pattern:RegExp(/(^|["'\s])/.source+"(?:"+e+")"+/\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))/.source,"i"),lookbehind:!0,inside:{"attr-name":/^[^\s=]+/,"attr-value":{pattern:/=[\s\S]+/,inside:{value:{pattern:/(^=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/,lookbehind:!0,alias:[t,"language-"+t],inside:r.languages[t]},punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}}}})}}),r.languages.html=r.languages.markup,r.languages.mathml=r.languages.markup,r.languages.svg=r.languages.markup,r.languages.xml=r.languages.extend("markup",{}),r.languages.ssml=r.languages.xml,r.languages.atom=r.languages.xml,r.languages.rss=r.languages.xml,function(e){var t="\\b(?:BASH|BASHOPTS|BASH_ALIASES|BASH_ARGC|BASH_ARGV|BASH_CMDS|BASH_COMPLETION_COMPAT_DIR|BASH_LINENO|BASH_REMATCH|BASH_SOURCE|BASH_VERSINFO|BASH_VERSION|COLORTERM|COLUMNS|COMP_WORDBREAKS|DBUS_SESSION_BUS_ADDRESS|DEFAULTS_PATH|DESKTOP_SESSION|DIRSTACK|DISPLAY|EUID|GDMSESSION|GDM_LANG|GNOME_KEYRING_CONTROL|GNOME_KEYRING_PID|GPG_AGENT_INFO|GROUPS|HISTCONTROL|HISTFILE|HISTFILESIZE|HISTSIZE|HOME|HOSTNAME|HOSTTYPE|IFS|INSTANCE|JOB|LANG|LANGUAGE|LC_ADDRESS|LC_ALL|LC_IDENTIFICATION|LC_MEASUREMENT|LC_MONETARY|LC_NAME|LC_NUMERIC|LC_PAPER|LC_TELEPHONE|LC_TIME|LESSCLOSE|LESSOPEN|LINES|LOGNAME|LS_COLORS|MACHTYPE|MAILCHECK|MANDATORY_PATH|NO_AT_BRIDGE|OLDPWD|OPTERR|OPTIND|ORBIT_SOCKETDIR|OSTYPE|PAPERSIZE|PATH|PIPESTATUS|PPID|PS1|PS2|PS3|PS4|PWD|RANDOM|REPLY|SECONDS|SELINUX_INIT|SESSION|SESSIONTYPE|SESSION_MANAGER|SHELL|SHELLOPTS|SHLVL|SSH_AUTH_SOCK|TERM|UID|UPSTART_EVENTS|UPSTART_INSTANCE|UPSTART_JOB|UPSTART_SESSION|USER|WINDOWID|XAUTHORITY|XDG_CONFIG_DIRS|XDG_CURRENT_DESKTOP|XDG_DATA_DIRS|XDG_GREETER_DATA_DIR|XDG_MENU_PREFIX|XDG_RUNTIME_DIR|XDG_SEAT|XDG_SEAT_PATH|XDG_SESSION_DESKTOP|XDG_SESSION_ID|XDG_SESSION_PATH|XDG_SESSION_TYPE|XDG_VTNR|XMODIFIERS)\\b",n={pattern:/(^(["']?)\w+\2)[ \t]+\S.*/,lookbehind:!0,alias:"punctuation",inside:null},a={bash:n,environment:{pattern:RegExp("\\$"+t),alias:"constant"},variable:[{pattern:/\$?\(\([\s\S]+?\)\)/,greedy:!0,inside:{variable:[{pattern:/(^\$\(\([\s\S]+)\)\)/,lookbehind:!0},/^\$\(\(/],number:/\b0x[\dA-Fa-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[Ee]-?\d+)?/,operator:/--|\+\+|\*\*=?|<<=?|>>=?|&&|\|\||[=!+\-*/%<>^&|]=?|[?~:]/,punctuation:/\(\(?|\)\)?|,|;/}},{pattern:/\$\((?:\([^)]+\)|[^()])+\)|`[^`]+`/,greedy:!0,inside:{variable:/^\$\(|^`|\)$|`$/}},{pattern:/\$\{[^}]+\}/,greedy:!0,inside:{operator:/:[-=?+]?|[!\/]|##?|%%?|\^\^?|,,?/,punctuation:/[\[\]]/,environment:{pattern:RegExp("(\\{)"+t),lookbehind:!0,alias:"constant"}}},/\$(?:\w+|[#?*!@$])/],entity:/\\(?:[abceEfnrtv\\"]|O?[0-7]{1,3}|U[0-9a-fA-F]{8}|u[0-9a-fA-F]{4}|x[0-9a-fA-F]{1,2})/};e.languages.bash={shebang:{pattern:/^#!\s*\/.*/,alias:"important"},comment:{pattern:/(^|[^"{\\$])#.*/,lookbehind:!0},"function-name":[{pattern:/(\bfunction\s+)[\w-]+(?=(?:\s*\(?:\s*\))?\s*\{)/,lookbehind:!0,alias:"function"},{pattern:/\b[\w-]+(?=\s*\(\s*\)\s*\{)/,alias:"function"}],"for-or-select":{pattern:/(\b(?:for|select)\s+)\w+(?=\s+in\s)/,alias:"variable",lookbehind:!0},"assign-left":{pattern:/(^|[\s;|&]|[<>]\()\w+(?=\+?=)/,inside:{environment:{pattern:RegExp("(^|[\\s;|&]|[<>]\\()"+t),lookbehind:!0,alias:"constant"}},alias:"variable",lookbehind:!0},string:[{pattern:/((?:^|[^<])<<-?\s*)(\w+)\s[\s\S]*?(?:\r?\n|\r)\2/,lookbehind:!0,greedy:!0,inside:a},{pattern:/((?:^|[^<])<<-?\s*)(["'])(\w+)\2\s[\s\S]*?(?:\r?\n|\r)\3/,lookbehind:!0,greedy:!0,inside:{bash:n}},{pattern:/(^|[^\\](?:\\\\)*)"(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|[^"\\`$])*"/,lookbehind:!0,greedy:!0,inside:a},{pattern:/(^|[^$\\])'[^']*'/,lookbehind:!0,greedy:!0},{pattern:/\$'(?:[^'\\]|\\[\s\S])*'/,greedy:!0,inside:{entity:a.entity}}],environment:{pattern:RegExp("\\$?"+t),alias:"constant"},variable:a.variable,function:{pattern:/(^|[\s;|&]|[<>]\()(?:add|apropos|apt|apt-cache|apt-get|aptitude|aspell|automysqlbackup|awk|basename|bash|bc|bconsole|bg|bzip2|cal|cat|cfdisk|chgrp|chkconfig|chmod|chown|chroot|cksum|clear|cmp|column|comm|composer|cp|cron|crontab|csplit|curl|cut|date|dc|dd|ddrescue|debootstrap|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|docker|docker-compose|du|egrep|eject|env|ethtool|expand|expect|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|git|gparted|grep|groupadd|groupdel|groupmod|groups|grub-mkconfig|gzip|halt|head|hg|history|host|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|ip|jobs|join|kill|killall|less|link|ln|locate|logname|logrotate|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|lynx|make|man|mc|mdadm|mkconfig|mkdir|mke2fs|mkfifo|mkfs|mkisofs|mknod|mkswap|mmv|more|most|mount|mtools|mtr|mutt|mv|nano|nc|netstat|nice|nl|node|nohup|notify-send|npm|nslookup|op|open|parted|passwd|paste|pathchk|ping|pkill|pnpm|podman|podman-compose|popd|pr|printcap|printenv|ps|pushd|pv|quota|quotacheck|quotactl|ram|rar|rcp|reboot|remsync|rename|renice|rev|rm|rmdir|rpm|rsync|scp|screen|sdiff|sed|sendmail|seq|service|sftp|sh|shellcheck|shuf|shutdown|sleep|slocate|sort|split|ssh|stat|strace|su|sudo|sum|suspend|swapon|sync|tac|tail|tar|tee|time|timeout|top|touch|tr|traceroute|tsort|tty|umount|uname|unexpand|uniq|units|unrar|unshar|unzip|update-grub|uptime|useradd|userdel|usermod|users|uudecode|uuencode|v|vcpkg|vdir|vi|vim|virsh|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yarn|yes|zenity|zip|zsh|zypper)(?=$|[)\s;|&])/,lookbehind:!0},keyword:{pattern:/(^|[\s;|&]|[<>]\()(?:case|do|done|elif|else|esac|fi|for|function|if|in|select|then|until|while)(?=$|[)\s;|&])/,lookbehind:!0},builtin:{pattern:/(^|[\s;|&]|[<>]\()(?:\.|:|alias|bind|break|builtin|caller|cd|command|continue|declare|echo|enable|eval|exec|exit|export|getopts|hash|help|let|local|logout|mapfile|printf|pwd|read|readarray|readonly|return|set|shift|shopt|source|test|times|trap|type|typeset|ulimit|umask|unalias|unset)(?=$|[)\s;|&])/,lookbehind:!0,alias:"class-name"},boolean:{pattern:/(^|[\s;|&]|[<>]\()(?:false|true)(?=$|[)\s;|&])/,lookbehind:!0},"file-descriptor":{pattern:/\B&\d\b/,alias:"important"},operator:{pattern:/\d?<>|>\||\+=|=[=~]?|!=?|<<[<-]?|[&\d]?>>|\d[<>]&?|[<>][&=]?|&[>&]?|\|[&|]?/,inside:{"file-descriptor":{pattern:/^\d/,alias:"important"}}},punctuation:/\$?\(\(?|\)\)?|\.\.|[{}[\];\\]/,number:{pattern:/(^|\s)(?:[1-9]\d*|0)(?:[.,]\d+)?\b/,lookbehind:!0}},n.inside=e.languages.bash;for(var r=["comment","function-name","for-or-select","assign-left","string","environment","function","keyword","builtin","boolean","file-descriptor","operator","punctuation","number"],o=a.variable[1].inside,s=0;s<r.length;s++)o[r[s]]=e.languages.bash[r[s]];e.languages.shell=e.languages.bash}(r),r.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0,greedy:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/(\b(?:class|extends|implements|instanceof|interface|new|trait)\s+|\bcatch\s+\()[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:break|catch|continue|do|else|finally|for|function|if|in|instanceof|new|null|return|throw|try|while)\b/,boolean:/\b(?:false|true)\b/,function:/\b\w+(?=\()/,number:/\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i,operator:/[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,punctuation:/[{}[\];(),.:]/},r.languages.c=r.languages.extend("clike",{comment:{pattern:/\/\/(?:[^\r\n\\]|\\(?:\r\n?|\n|(?![\r\n])))*|\/\*[\s\S]*?(?:\*\/|$)/,greedy:!0},string:{pattern:/"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"/,greedy:!0},"class-name":{pattern:/(\b(?:enum|struct)\s+(?:__attribute__\s*\(\([\s\S]*?\)\)\s*)?)\w+|\b[a-z]\w*_t\b/,lookbehind:!0},keyword:/\b(?:_Alignas|_Alignof|_Atomic|_Bool|_Complex|_Generic|_Imaginary|_Noreturn|_Static_assert|_Thread_local|__attribute__|asm|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|inline|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|typeof|union|unsigned|void|volatile|while)\b/,function:/\b[a-z_]\w*(?=\s*\()/i,number:/(?:\b0x(?:[\da-f]+(?:\.[\da-f]*)?|\.[\da-f]+)(?:p[+-]?\d+)?|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?)[ful]{0,4}/i,operator:/>>=?|<<=?|->|([-+&|:])\1|[?:~]|[-+*/%&|^!=<>]=?/}),r.languages.insertBefore("c","string",{char:{pattern:/'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n]){0,32}'/,greedy:!0}}),r.languages.insertBefore("c","string",{macro:{pattern:/(^[\t ]*)#\s*[a-z](?:[^\r\n\\/]|\/(?!\*)|\/\*(?:[^*]|\*(?!\/))*\*\/|\\(?:\r\n|[\s\S]))*/im,lookbehind:!0,greedy:!0,alias:"property",inside:{string:[{pattern:/^(#\s*include\s*)<[^>]+>/,lookbehind:!0},r.languages.c.string],char:r.languages.c.char,comment:r.languages.c.comment,"macro-name":[{pattern:/(^#\s*define\s+)\w+\b(?!\()/i,lookbehind:!0},{pattern:/(^#\s*define\s+)\w+\b(?=\()/i,lookbehind:!0,alias:"function"}],directive:{pattern:/^(#\s*)[a-z]+/,lookbehind:!0,alias:"keyword"},"directive-hash":/^#/,punctuation:/##|\\(?=[\r\n])/,expression:{pattern:/\S[\s\S]*/,inside:r.languages.c}}}}),r.languages.insertBefore("c","function",{constant:/\b(?:EOF|NULL|SEEK_CUR|SEEK_END|SEEK_SET|__DATE__|__FILE__|__LINE__|__TIMESTAMP__|__TIME__|__func__|stderr|stdin|stdout)\b/}),delete r.languages.c.boolean,function(e){var t=/\b(?:alignas|alignof|asm|auto|bool|break|case|catch|char|char16_t|char32_t|char8_t|class|co_await|co_return|co_yield|compl|concept|const|const_cast|consteval|constexpr|constinit|continue|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|final|float|for|friend|goto|if|import|inline|int|int16_t|int32_t|int64_t|int8_t|long|module|mutable|namespace|new|noexcept|nullptr|operator|override|private|protected|public|register|reinterpret_cast|requires|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|uint16_t|uint32_t|uint64_t|uint8_t|union|unsigned|using|virtual|void|volatile|wchar_t|while)\b/,n=/\b(?!<keyword>)\w+(?:\s*\.\s*\w+)*\b/.source.replace(/<keyword>/g,(function(){return t.source}));e.languages.cpp=e.languages.extend("c",{"class-name":[{pattern:RegExp(/(\b(?:class|concept|enum|struct|typename)\s+)(?!<keyword>)\w+/.source.replace(/<keyword>/g,(function(){return t.source}))),lookbehind:!0},/\b[A-Z]\w*(?=\s*::\s*\w+\s*\()/,/\b[A-Z_]\w*(?=\s*::\s*~\w+\s*\()/i,/\b\w+(?=\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>\s*::\s*\w+\s*\()/],keyword:t,number:{pattern:/(?:\b0b[01']+|\b0x(?:[\da-f']+(?:\.[\da-f']*)?|\.[\da-f']+)(?:p[+-]?[\d']+)?|(?:\b[\d']+(?:\.[\d']*)?|\B\.[\d']+)(?:e[+-]?[\d']+)?)[ful]{0,4}/i,greedy:!0},operator:/>>=?|<<=?|->|--|\+\+|&&|\|\||[?:~]|<=>|[-+*/%&|^!=<>]=?|\b(?:and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/,boolean:/\b(?:false|true)\b/}),e.languages.insertBefore("cpp","string",{module:{pattern:RegExp(/(\b(?:import|module)\s+)/.source+"(?:"+/"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|<[^<>\r\n]*>/.source+"|"+/<mod-name>(?:\s*:\s*<mod-name>)?|:\s*<mod-name>/.source.replace(/<mod-name>/g,(function(){return n}))+")"),lookbehind:!0,greedy:!0,inside:{string:/^[<"][\s\S]+/,operator:/:/,punctuation:/\./}},"raw-string":{pattern:/R"([^()\\ ]{0,16})\([\s\S]*?\)\1"/,alias:"string",greedy:!0}}),e.languages.insertBefore("cpp","keyword",{"generic-function":{pattern:/\b(?!operator\b)[a-z_]\w*\s*<(?:[^<>]|<[^<>]*>)*>(?=\s*\()/i,inside:{function:/^\w+/,generic:{pattern:/<[\s\S]+/,alias:"class-name",inside:e.languages.cpp}}}}),e.languages.insertBefore("cpp","operator",{"double-colon":{pattern:/::/,alias:"punctuation"}}),e.languages.insertBefore("cpp","class-name",{"base-clause":{pattern:/(\b(?:class|struct)\s+\w+\s*:\s*)[^;{}"'\s]+(?:\s+[^;{}"'\s]+)*(?=\s*[;{])/,lookbehind:!0,greedy:!0,inside:e.languages.extend("cpp",{})}}),e.languages.insertBefore("inside","double-colon",{"class-name":/\b[a-z_]\w*\b(?!\s*::)/i},e.languages.cpp["base-clause"])}(r),function(e){var t=/(?:"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n])*')/;e.languages.css={comment:/\/\*[\s\S]*?\*\//,atrule:{pattern:/@[\w-](?:[^;{\s]|\s+(?![\s{]))*(?:;|(?=\s*\{))/,inside:{rule:/^@[\w-]+/,"selector-function-argument":{pattern:/(\bselector\s*\(\s*(?![\s)]))(?:[^()\s]|\s+(?![\s)])|\((?:[^()]|\([^()]*\))*\))+(?=\s*\))/,lookbehind:!0,alias:"selector"},keyword:{pattern:/(^|[^\w-])(?:and|not|only|or)(?![\w-])/,lookbehind:!0}}},url:{pattern:RegExp("\\burl\\((?:"+t.source+"|"+/(?:[^\\\r\n()"']|\\[\s\S])*/.source+")\\)","i"),greedy:!0,inside:{function:/^url/i,punctuation:/^\(|\)$/,string:{pattern:RegExp("^"+t.source+"$"),alias:"url"}}},selector:{pattern:RegExp("(^|[{}\\s])[^{}\\s](?:[^{};\"'\\s]|\\s+(?![\\s{])|"+t.source+")*(?=\\s*\\{)"),lookbehind:!0},string:{pattern:t,greedy:!0},property:{pattern:/(^|[^-\w\xA0-\uFFFF])(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*(?=\s*:)/i,lookbehind:!0},important:/!important\b/i,function:{pattern:/(^|[^-a-z0-9])[-a-z0-9]+(?=\()/i,lookbehind:!0},punctuation:/[(){};:,]/},e.languages.css.atrule.inside.rest=e.languages.css;var n=e.languages.markup;n&&(n.tag.addInlined("style","css"),n.tag.addAttribute("style","css"))}(r),function(e){var t,n=/("|')(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/;e.languages.css.selector={pattern:e.languages.css.selector.pattern,lookbehind:!0,inside:t={"pseudo-element":/:(?:after|before|first-letter|first-line|selection)|::[-\w]+/,"pseudo-class":/:[-\w]+/,class:/\.[-\w]+/,id:/#[-\w]+/,attribute:{pattern:RegExp("\\[(?:[^[\\]\"']|"+n.source+")*\\]"),greedy:!0,inside:{punctuation:/^\[|\]$/,"case-sensitivity":{pattern:/(\s)[si]$/i,lookbehind:!0,alias:"keyword"},namespace:{pattern:/^(\s*)(?:(?!\s)[-*\w\xA0-\uFFFF])*\|(?!=)/,lookbehind:!0,inside:{punctuation:/\|$/}},"attr-name":{pattern:/^(\s*)(?:(?!\s)[-\w\xA0-\uFFFF])+/,lookbehind:!0},"attr-value":[n,{pattern:/(=\s*)(?:(?!\s)[-\w\xA0-\uFFFF])+(?=\s*$)/,lookbehind:!0}],operator:/[|~*^$]?=/}},"n-th":[{pattern:/(\(\s*)[+-]?\d*[\dn](?:\s*[+-]\s*\d+)?(?=\s*\))/,lookbehind:!0,inside:{number:/[\dn]+/,operator:/[+-]/}},{pattern:/(\(\s*)(?:even|odd)(?=\s*\))/i,lookbehind:!0}],combinator:/>|\+|~|\|\|/,punctuation:/[(),]/}},e.languages.css.atrule.inside["selector-function-argument"].inside=t,e.languages.insertBefore("css","property",{variable:{pattern:/(^|[^-\w\xA0-\uFFFF])--(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*/i,lookbehind:!0}});var a={pattern:/(\b\d+)(?:%|[a-z]+(?![\w-]))/,lookbehind:!0},r={pattern:/(^|[^\w.-])-?(?:\d+(?:\.\d+)?|\.\d+)/,lookbehind:!0};e.languages.insertBefore("css","function",{operator:{pattern:/(\s)[+\-*\/](?=\s)/,lookbehind:!0},hexcode:{pattern:/\B#[\da-f]{3,8}\b/i,alias:"color"},color:[{pattern:/(^|[^\w-])(?:AliceBlue|AntiqueWhite|Aqua|Aquamarine|Azure|Beige|Bisque|Black|BlanchedAlmond|Blue|BlueViolet|Brown|BurlyWood|CadetBlue|Chartreuse|Chocolate|Coral|CornflowerBlue|Cornsilk|Crimson|Cyan|DarkBlue|DarkCyan|DarkGoldenRod|DarkGr[ae]y|DarkGreen|DarkKhaki|DarkMagenta|DarkOliveGreen|DarkOrange|DarkOrchid|DarkRed|DarkSalmon|DarkSeaGreen|DarkSlateBlue|DarkSlateGr[ae]y|DarkTurquoise|DarkViolet|DeepPink|DeepSkyBlue|DimGr[ae]y|DodgerBlue|FireBrick|FloralWhite|ForestGreen|Fuchsia|Gainsboro|GhostWhite|Gold|GoldenRod|Gr[ae]y|Green|GreenYellow|HoneyDew|HotPink|IndianRed|Indigo|Ivory|Khaki|Lavender|LavenderBlush|LawnGreen|LemonChiffon|LightBlue|LightCoral|LightCyan|LightGoldenRodYellow|LightGr[ae]y|LightGreen|LightPink|LightSalmon|LightSeaGreen|LightSkyBlue|LightSlateGr[ae]y|LightSteelBlue|LightYellow|Lime|LimeGreen|Linen|Magenta|Maroon|MediumAquaMarine|MediumBlue|MediumOrchid|MediumPurple|MediumSeaGreen|MediumSlateBlue|MediumSpringGreen|MediumTurquoise|MediumVioletRed|MidnightBlue|MintCream|MistyRose|Moccasin|NavajoWhite|Navy|OldLace|Olive|OliveDrab|Orange|OrangeRed|Orchid|PaleGoldenRod|PaleGreen|PaleTurquoise|PaleVioletRed|PapayaWhip|PeachPuff|Peru|Pink|Plum|PowderBlue|Purple|Red|RosyBrown|RoyalBlue|SaddleBrown|Salmon|SandyBrown|SeaGreen|SeaShell|Sienna|Silver|SkyBlue|SlateBlue|SlateGr[ae]y|Snow|SpringGreen|SteelBlue|Tan|Teal|Thistle|Tomato|Transparent|Turquoise|Violet|Wheat|White|WhiteSmoke|Yellow|YellowGreen)(?![\w-])/i,lookbehind:!0},{pattern:/\b(?:hsl|rgb)\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*\)\B|\b(?:hsl|rgb)a\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*,\s*(?:0|0?\.\d+|1)\s*\)\B/i,inside:{unit:a,number:r,function:/[\w-]+(?=\()/,punctuation:/[(),]/}}],entity:/\\[\da-f]{1,8}/i,unit:a,number:r})}(r),r.languages.javascript=r.languages.extend("clike",{"class-name":[r.languages.clike["class-name"],{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$A-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\.(?:constructor|prototype))/,lookbehind:!0}],keyword:[{pattern:/((?:^|\})\s*)catch\b/,lookbehind:!0},{pattern:/(^|[^.]|\.\.\.\s*)\b(?:as|assert(?=\s*\{)|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally(?=\s*(?:\{|$))|for|from(?=\s*(?:['"]|$))|function|(?:get|set)(?=\s*(?:[#\[$\w\xA0-\uFFFF]|$))|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,lookbehind:!0}],function:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,number:{pattern:RegExp(/(^|[^\w$])/.source+"(?:"+/NaN|Infinity/.source+"|"+/0[bB][01]+(?:_[01]+)*n?/.source+"|"+/0[oO][0-7]+(?:_[0-7]+)*n?/.source+"|"+/0[xX][\dA-Fa-f]+(?:_[\dA-Fa-f]+)*n?/.source+"|"+/\d+(?:_\d+)*n/.source+"|"+/(?:\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\.\d+(?:_\d+)*)(?:[Ee][+-]?\d+(?:_\d+)*)?/.source+")"+/(?![\w$])/.source),lookbehind:!0},operator:/--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/}),r.languages.javascript["class-name"][0].pattern=/(\b(?:class|extends|implements|instanceof|interface|new)\s+)[\w.\\]+/,r.languages.insertBefore("javascript","keyword",{regex:{pattern:/((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)\/(?:\[(?:[^\]\\\r\n]|\\.)*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/,lookbehind:!0,greedy:!0,inside:{"regex-source":{pattern:/^(\/)[\s\S]+(?=\/[a-z]*$)/,lookbehind:!0,alias:"language-regex",inside:r.languages.regex},"regex-delimiter":/^\/|\/$/,"regex-flags":/^[a-z]+$/}},"function-variable":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/,alias:"function"},parameter:[{pattern:/(function(?:\s+(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)?\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\))/,lookbehind:!0,inside:r.languages.javascript},{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=>)/i,lookbehind:!0,inside:r.languages.javascript},{pattern:/(\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*=>)/,lookbehind:!0,inside:r.languages.javascript},{pattern:/((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*\{)/,lookbehind:!0,inside:r.languages.javascript}],constant:/\b[A-Z](?:[A-Z_]|\dx?)*\b/}),r.languages.insertBefore("javascript","string",{hashbang:{pattern:/^#!.*/,greedy:!0,alias:"comment"},"template-string":{pattern:/`(?:\\[\s\S]|\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}|(?!\$\{)[^\\`])*`/,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}/,lookbehind:!0,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:r.languages.javascript}},string:/[\s\S]+/}},"string-property":{pattern:/((?:^|[,{])[ \t]*)(["'])(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2(?=\s*:)/m,lookbehind:!0,greedy:!0,alias:"property"}}),r.languages.insertBefore("javascript","operator",{"literal-property":{pattern:/((?:^|[,{])[ \t]*)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*:)/m,lookbehind:!0,alias:"property"}}),r.languages.markup&&(r.languages.markup.tag.addInlined("script","javascript"),r.languages.markup.tag.addAttribute(/on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)/.source,"javascript")),r.languages.js=r.languages.javascript,function(e){var t=/#(?!\{).+/,n={pattern:/#\{[^}]+\}/,alias:"variable"};e.languages.coffeescript=e.languages.extend("javascript",{comment:t,string:[{pattern:/'(?:\\[\s\S]|[^\\'])*'/,greedy:!0},{pattern:/"(?:\\[\s\S]|[^\\"])*"/,greedy:!0,inside:{interpolation:n}}],keyword:/\b(?:and|break|by|catch|class|continue|debugger|delete|do|each|else|extend|extends|false|finally|for|if|in|instanceof|is|isnt|let|loop|namespace|new|no|not|null|of|off|on|or|own|return|super|switch|then|this|throw|true|try|typeof|undefined|unless|until|when|while|window|with|yes|yield)\b/,"class-member":{pattern:/@(?!\d)\w+/,alias:"variable"}}),e.languages.insertBefore("coffeescript","comment",{"multiline-comment":{pattern:/###[\s\S]+?###/,alias:"comment"},"block-regex":{pattern:/\/{3}[\s\S]*?\/{3}/,alias:"regex",inside:{comment:t,interpolation:n}}}),e.languages.insertBefore("coffeescript","string",{"inline-javascript":{pattern:/`(?:\\[\s\S]|[^\\`])*`/,inside:{delimiter:{pattern:/^`|`$/,alias:"punctuation"},script:{pattern:/[\s\S]+/,alias:"language-javascript",inside:e.languages.javascript}}},"multiline-string":[{pattern:/'''[\s\S]*?'''/,greedy:!0,alias:"string"},{pattern:/"""[\s\S]*?"""/,greedy:!0,alias:"string",inside:{interpolation:n}}]}),e.languages.insertBefore("coffeescript","keyword",{property:/(?!\d)\w+(?=\s*:(?!:))/}),delete e.languages.coffeescript["template-string"],e.languages.coffee=e.languages.coffeescript}(r),function(e){var t=/[*&][^\s[\]{},]+/,n=/!(?:<[\w\-%#;/?:@&=+$,.!~*'()[\]]+>|(?:[a-zA-Z\d-]*!)?[\w\-%#;/?:@&=+$.~*'()]+)?/,a="(?:"+n.source+"(?:[ \t]+"+t.source+")?|"+t.source+"(?:[ \t]+"+n.source+")?)",r=/(?:[^\s\x00-\x08\x0e-\x1f!"#%&'*,\-:>?@[\]`{|}\x7f-\x84\x86-\x9f\ud800-\udfff\ufffe\uffff]|[?:-]<PLAIN>)(?:[ \t]*(?:(?![#:])<PLAIN>|:<PLAIN>))*/.source.replace(/<PLAIN>/g,(function(){return/[^\s\x00-\x08\x0e-\x1f,[\]{}\x7f-\x84\x86-\x9f\ud800-\udfff\ufffe\uffff]/.source})),o=/"(?:[^"\\\r\n]|\\.)*"|'(?:[^'\\\r\n]|\\.)*'/.source;function s(e,t){t=(t||"").replace(/m/g,"")+"m";var n=/([:\-,[{]\s*(?:\s<<prop>>[ \t]+)?)(?:<<value>>)(?=[ \t]*(?:$|,|\]|\}|(?:[\r\n]\s*)?#))/.source.replace(/<<prop>>/g,(function(){return a})).replace(/<<value>>/g,(function(){return e}));return RegExp(n,t)}e.languages.yaml={scalar:{pattern:RegExp(/([\-:]\s*(?:\s<<prop>>[ \t]+)?[|>])[ \t]*(?:((?:\r?\n|\r)[ \t]+)\S[^\r\n]*(?:\2[^\r\n]+)*)/.source.replace(/<<prop>>/g,(function(){return a}))),lookbehind:!0,alias:"string"},comment:/#.*/,key:{pattern:RegExp(/((?:^|[:\-,[{\r\n?])[ \t]*(?:<<prop>>[ \t]+)?)<<key>>(?=\s*:\s)/.source.replace(/<<prop>>/g,(function(){return a})).replace(/<<key>>/g,(function(){return"(?:"+r+"|"+o+")"}))),lookbehind:!0,greedy:!0,alias:"atrule"},directive:{pattern:/(^[ \t]*)%.+/m,lookbehind:!0,alias:"important"},datetime:{pattern:s(/\d{4}-\d\d?-\d\d?(?:[tT]|[ \t]+)\d\d?:\d{2}:\d{2}(?:\.\d*)?(?:[ \t]*(?:Z|[-+]\d\d?(?::\d{2})?))?|\d{4}-\d{2}-\d{2}|\d\d?:\d{2}(?::\d{2}(?:\.\d*)?)?/.source),lookbehind:!0,alias:"number"},boolean:{pattern:s(/false|true/.source,"i"),lookbehind:!0,alias:"important"},null:{pattern:s(/null|~/.source,"i"),lookbehind:!0,alias:"important"},string:{pattern:s(o),lookbehind:!0,greedy:!0},number:{pattern:s(/[+-]?(?:0x[\da-f]+|0o[0-7]+|(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?|\.inf|\.nan)/.source,"i"),lookbehind:!0},tag:n,important:t,punctuation:/---|[:[\]{}\-,|>?]|\.\.\./},e.languages.yml=e.languages.yaml}(r),function(e){var t=/(?:\\.|[^\\\n\r]|(?:\n|\r\n?)(?![\r\n]))/.source;function n(e){return e=e.replace(/<inner>/g,(function(){return t})),RegExp(/((?:^|[^\\])(?:\\{2})*)/.source+"(?:"+e+")")}var a=/(?:\\.|``(?:[^`\r\n]|`(?!`))+``|`[^`\r\n]+`|[^\\|\r\n`])+/.source,r=/\|?__(?:\|__)+\|?(?:(?:\n|\r\n?)|(?![\s\S]))/.source.replace(/__/g,(function(){return a})),o=/\|?[ \t]*:?-{3,}:?[ \t]*(?:\|[ \t]*:?-{3,}:?[ \t]*)+\|?(?:\n|\r\n?)/.source;e.languages.markdown=e.languages.extend("markup",{}),e.languages.insertBefore("markdown","prolog",{"front-matter-block":{pattern:/(^(?:\s*[\r\n])?)---(?!.)[\s\S]*?[\r\n]---(?!.)/,lookbehind:!0,greedy:!0,inside:{punctuation:/^---|---$/,"front-matter":{pattern:/\S+(?:\s+\S+)*/,alias:["yaml","language-yaml"],inside:e.languages.yaml}}},blockquote:{pattern:/^>(?:[\t ]*>)*/m,alias:"punctuation"},table:{pattern:RegExp("^"+r+o+"(?:"+r+")*","m"),inside:{"table-data-rows":{pattern:RegExp("^("+r+o+")(?:"+r+")*$"),lookbehind:!0,inside:{"table-data":{pattern:RegExp(a),inside:e.languages.markdown},punctuation:/\|/}},"table-line":{pattern:RegExp("^("+r+")"+o+"$"),lookbehind:!0,inside:{punctuation:/\||:?-{3,}:?/}},"table-header-row":{pattern:RegExp("^"+r+"$"),inside:{"table-header":{pattern:RegExp(a),alias:"important",inside:e.languages.markdown},punctuation:/\|/}}}},code:[{pattern:/((?:^|\n)[ \t]*\n|(?:^|\r\n?)[ \t]*\r\n?)(?: {4}|\t).+(?:(?:\n|\r\n?)(?: {4}|\t).+)*/,lookbehind:!0,alias:"keyword"},{pattern:/^```[\s\S]*?^```$/m,greedy:!0,inside:{"code-block":{pattern:/^(```.*(?:\n|\r\n?))[\s\S]+?(?=(?:\n|\r\n?)^```$)/m,lookbehind:!0},"code-language":{pattern:/^(```).+/,lookbehind:!0},punctuation:/```/}}],title:[{pattern:/\S.*(?:\n|\r\n?)(?:==+|--+)(?=[ \t]*$)/m,alias:"important",inside:{punctuation:/==+$|--+$/}},{pattern:/(^\s*)#.+/m,lookbehind:!0,alias:"important",inside:{punctuation:/^#+|#+$/}}],hr:{pattern:/(^\s*)([*-])(?:[\t ]*\2){2,}(?=\s*$)/m,lookbehind:!0,alias:"punctuation"},list:{pattern:/(^\s*)(?:[*+-]|\d+\.)(?=[\t ].)/m,lookbehind:!0,alias:"punctuation"},"url-reference":{pattern:/!?\[[^\]]+\]:[\t ]+(?:\S+|<(?:\\.|[^>\\])+>)(?:[\t ]+(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\)))?/,inside:{variable:{pattern:/^(!?\[)[^\]]+/,lookbehind:!0},string:/(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\))$/,punctuation:/^[\[\]!:]|[<>]/},alias:"url"},bold:{pattern:n(/\b__(?:(?!_)<inner>|_(?:(?!_)<inner>)+_)+__\b|\*\*(?:(?!\*)<inner>|\*(?:(?!\*)<inner>)+\*)+\*\*/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^..)[\s\S]+(?=..$)/,lookbehind:!0,inside:{}},punctuation:/\*\*|__/}},italic:{pattern:n(/\b_(?:(?!_)<inner>|__(?:(?!_)<inner>)+__)+_\b|\*(?:(?!\*)<inner>|\*\*(?:(?!\*)<inner>)+\*\*)+\*/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^.)[\s\S]+(?=.$)/,lookbehind:!0,inside:{}},punctuation:/[*_]/}},strike:{pattern:n(/(~~?)(?:(?!~)<inner>)+\2/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^~~?)[\s\S]+(?=\1$)/,lookbehind:!0,inside:{}},punctuation:/~~?/}},"code-snippet":{pattern:/(^|[^\\`])(?:``[^`\r\n]+(?:`[^`\r\n]+)*``(?!`)|`[^`\r\n]+`(?!`))/,lookbehind:!0,greedy:!0,alias:["code","keyword"]},url:{pattern:n(/!?\[(?:(?!\])<inner>)+\](?:\([^\s)]+(?:[\t ]+"(?:\\.|[^"\\])*")?\)|[ \t]?\[(?:(?!\])<inner>)+\])/.source),lookbehind:!0,greedy:!0,inside:{operator:/^!/,content:{pattern:/(^\[)[^\]]+(?=\])/,lookbehind:!0,inside:{}},variable:{pattern:/(^\][ \t]?\[)[^\]]+(?=\]$)/,lookbehind:!0},url:{pattern:/(^\]\()[^\s)]+/,lookbehind:!0},string:{pattern:/(^[ \t]+)"(?:\\.|[^"\\])*"(?=\)$)/,lookbehind:!0}}}}),["url","bold","italic","strike"].forEach((function(t){["url","bold","italic","strike","code-snippet"].forEach((function(n){t!==n&&(e.languages.markdown[t].inside.content.inside[n]=e.languages.markdown[n])}))})),e.hooks.add("after-tokenize",(function(e){"markdown"!==e.language&&"md"!==e.language||function e(t){if(t&&"string"!=typeof t)for(var n=0,a=t.length;n<a;n++){var r=t[n];if("code"===r.type){var o=r.content[1],s=r.content[3];if(o&&s&&"code-language"===o.type&&"code-block"===s.type&&"string"==typeof o.content){var i=o.content.replace(/\b#/g,"sharp").replace(/\b\+\+/g,"pp"),l="language-"+(i=(/[a-z][\w-]*/i.exec(i)||[""])[0].toLowerCase());s.alias?"string"==typeof s.alias?s.alias=[s.alias,l]:s.alias.push(l):s.alias=[l]}}else e(r.content)}}(e.tokens)})),e.hooks.add("wrap",(function(t){if("code-block"===t.type){for(var n="",a=0,r=t.classes.length;a<r;a++){var o=t.classes[a],c=/language-(.+)/.exec(o);if(c){n=c[1];break}}var u,d=e.languages[n];if(d)t.content=e.highlight((u=t.content,u.replace(s,"").replace(/&(\w{1,8}|#x?[\da-f]{1,8});/gi,(function(e,t){var n;if("#"===(t=t.toLowerCase())[0])return n="x"===t[1]?parseInt(t.slice(2),16):Number(t.slice(1)),l(n);var a=i[t];return a||e}))),d,n);else if(n&&"none"!==n&&e.plugins.autoloader){var f="md-"+(new Date).valueOf()+"-"+Math.floor(1e16*Math.random());t.attributes.id=f,e.plugins.autoloader.loadLanguages(n,(function(){var t=document.getElementById(f);t&&(t.innerHTML=e.highlight(t.textContent,e.languages[n],n))}))}}}));var s=RegExp(e.languages.markup.tag.pattern.source,"gi"),i={amp:"&",lt:"<",gt:">",quot:'"'},l=String.fromCodePoint||String.fromCharCode;e.languages.md=e.languages.markdown}(r),r.languages.graphql={comment:/#.*/,description:{pattern:/(?:"""(?:[^"]|(?!""")")*"""|"(?:\\.|[^\\"\r\n])*")(?=\s*[a-z_])/i,greedy:!0,alias:"string",inside:{"language-markdown":{pattern:/(^"(?:"")?)(?!\1)[\s\S]+(?=\1$)/,lookbehind:!0,inside:r.languages.markdown}}},string:{pattern:/"""(?:[^"]|(?!""")")*"""|"(?:\\.|[^\\"\r\n])*"/,greedy:!0},number:/(?:\B-|\b)\d+(?:\.\d+)?(?:e[+-]?\d+)?\b/i,boolean:/\b(?:false|true)\b/,variable:/\$[a-z_]\w*/i,directive:{pattern:/@[a-z_]\w*/i,alias:"function"},"attr-name":{pattern:/\b[a-z_]\w*(?=\s*(?:\((?:[^()"]|"(?:\\.|[^\\"\r\n])*")*\))?:)/i,greedy:!0},"atom-input":{pattern:/\b[A-Z]\w*Input\b/,alias:"class-name"},scalar:/\b(?:Boolean|Float|ID|Int|String)\b/,constant:/\b[A-Z][A-Z_\d]*\b/,"class-name":{pattern:/(\b(?:enum|implements|interface|on|scalar|type|union)\s+|&\s*|:\s*|\[)[A-Z_]\w*/,lookbehind:!0},fragment:{pattern:/(\bfragment\s+|\.{3}\s*(?!on\b))[a-zA-Z_]\w*/,lookbehind:!0,alias:"function"},"definition-mutation":{pattern:/(\bmutation\s+)[a-zA-Z_]\w*/,lookbehind:!0,alias:"function"},"definition-query":{pattern:/(\bquery\s+)[a-zA-Z_]\w*/,lookbehind:!0,alias:"function"},keyword:/\b(?:directive|enum|extend|fragment|implements|input|interface|mutation|on|query|repeatable|scalar|schema|subscription|type|union)\b/,operator:/[!=|&]|\.{3}/,"property-query":/\w+(?=\s*\()/,object:/\w+(?=\s*\{)/,punctuation:/[!(){}\[\]:=,]/,property:/\w+/},r.hooks.add("after-tokenize",(function(e){if("graphql"===e.language)for(var t=e.tokens.filter((function(e){return"string"!=typeof e&&"comment"!==e.type&&"scalar"!==e.type})),n=0;n<t.length;){var a=t[n++];if("keyword"===a.type&&"mutation"===a.content){var r=[];if(d(["definition-mutation","punctuation"])&&"("===u(1).content){n+=2;var o=f(/^\($/,/^\)$/);if(-1===o)continue;for(;n<o;n++){var s=u(0);"variable"===s.type&&(p(s,"variable-input"),r.push(s.content))}n=o+1}if(d(["punctuation","property-query"])&&"{"===u(0).content&&(n++,p(u(0),"property-mutation"),r.length>0)){var i=f(/^\{$/,/^\}$/);if(-1===i)continue;for(var l=n;l<i;l++){var c=t[l];"variable"===c.type&&r.indexOf(c.content)>=0&&p(c,"variable-input")}}}}function u(e){return t[n+e]}function d(e,t){t=t||0;for(var n=0;n<e.length;n++){var a=u(n+t);if(!a||a.type!==e[n])return!1}return!0}function f(e,a){for(var r=1,o=n;o<t.length;o++){var s=t[o],i=s.content;if("punctuation"===s.type&&"string"==typeof i)if(e.test(i))r++;else if(a.test(i)&&0===--r)return o}return-1}function p(e,t){var n=e.alias;n?Array.isArray(n)||(e.alias=n=[n]):e.alias=n=[],n.push(t)}})),r.languages.sql={comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|(?:--|\/\/|#).*)/,lookbehind:!0},variable:[{pattern:/@(["'`])(?:\\[\s\S]|(?!\1)[^\\])+\1/,greedy:!0},/@[\w.$]+/],string:{pattern:/(^|[^@\\])("|')(?:\\[\s\S]|(?!\2)[^\\]|\2\2)*\2/,greedy:!0,lookbehind:!0},identifier:{pattern:/(^|[^@\\])`(?:\\[\s\S]|[^`\\]|``)*`/,greedy:!0,lookbehind:!0,inside:{punctuation:/^`|`$/}},function:/\b(?:AVG|COUNT|FIRST|FORMAT|LAST|LCASE|LEN|MAX|MID|MIN|MOD|NOW|ROUND|SUM|UCASE)(?=\s*\()/i,keyword:/\b(?:ACTION|ADD|AFTER|ALGORITHM|ALL|ALTER|ANALYZE|ANY|APPLY|AS|ASC|AUTHORIZATION|AUTO_INCREMENT|BACKUP|BDB|BEGIN|BERKELEYDB|BIGINT|BINARY|BIT|BLOB|BOOL|BOOLEAN|BREAK|BROWSE|BTREE|BULK|BY|CALL|CASCADED?|CASE|CHAIN|CHAR(?:ACTER|SET)?|CHECK(?:POINT)?|CLOSE|CLUSTERED|COALESCE|COLLATE|COLUMNS?|COMMENT|COMMIT(?:TED)?|COMPUTE|CONNECT|CONSISTENT|CONSTRAINT|CONTAINS(?:TABLE)?|CONTINUE|CONVERT|CREATE|CROSS|CURRENT(?:_DATE|_TIME|_TIMESTAMP|_USER)?|CURSOR|CYCLE|DATA(?:BASES?)?|DATE(?:TIME)?|DAY|DBCC|DEALLOCATE|DEC|DECIMAL|DECLARE|DEFAULT|DEFINER|DELAYED|DELETE|DELIMITERS?|DENY|DESC|DESCRIBE|DETERMINISTIC|DISABLE|DISCARD|DISK|DISTINCT|DISTINCTROW|DISTRIBUTED|DO|DOUBLE|DROP|DUMMY|DUMP(?:FILE)?|DUPLICATE|ELSE(?:IF)?|ENABLE|ENCLOSED|END|ENGINE|ENUM|ERRLVL|ERRORS|ESCAPED?|EXCEPT|EXEC(?:UTE)?|EXISTS|EXIT|EXPLAIN|EXTENDED|FETCH|FIELDS|FILE|FILLFACTOR|FIRST|FIXED|FLOAT|FOLLOWING|FOR(?: EACH ROW)?|FORCE|FOREIGN|FREETEXT(?:TABLE)?|FROM|FULL|FUNCTION|GEOMETRY(?:COLLECTION)?|GLOBAL|GOTO|GRANT|GROUP|HANDLER|HASH|HAVING|HOLDLOCK|HOUR|IDENTITY(?:COL|_INSERT)?|IF|IGNORE|IMPORT|INDEX|INFILE|INNER|INNODB|INOUT|INSERT|INT|INTEGER|INTERSECT|INTERVAL|INTO|INVOKER|ISOLATION|ITERATE|JOIN|KEYS?|KILL|LANGUAGE|LAST|LEAVE|LEFT|LEVEL|LIMIT|LINENO|LINES|LINESTRING|LOAD|LOCAL|LOCK|LONG(?:BLOB|TEXT)|LOOP|MATCH(?:ED)?|MEDIUM(?:BLOB|INT|TEXT)|MERGE|MIDDLEINT|MINUTE|MODE|MODIFIES|MODIFY|MONTH|MULTI(?:LINESTRING|POINT|POLYGON)|NATIONAL|NATURAL|NCHAR|NEXT|NO|NONCLUSTERED|NULLIF|NUMERIC|OFF?|OFFSETS?|ON|OPEN(?:DATASOURCE|QUERY|ROWSET)?|OPTIMIZE|OPTION(?:ALLY)?|ORDER|OUT(?:ER|FILE)?|OVER|PARTIAL|PARTITION|PERCENT|PIVOT|PLAN|POINT|POLYGON|PRECEDING|PRECISION|PREPARE|PREV|PRIMARY|PRINT|PRIVILEGES|PROC(?:EDURE)?|PUBLIC|PURGE|QUICK|RAISERROR|READS?|REAL|RECONFIGURE|REFERENCES|RELEASE|RENAME|REPEAT(?:ABLE)?|REPLACE|REPLICATION|REQUIRE|RESIGNAL|RESTORE|RESTRICT|RETURN(?:ING|S)?|REVOKE|RIGHT|ROLLBACK|ROUTINE|ROW(?:COUNT|GUIDCOL|S)?|RTREE|RULE|SAVE(?:POINT)?|SCHEMA|SECOND|SELECT|SERIAL(?:IZABLE)?|SESSION(?:_USER)?|SET(?:USER)?|SHARE|SHOW|SHUTDOWN|SIMPLE|SMALLINT|SNAPSHOT|SOME|SONAME|SQL|START(?:ING)?|STATISTICS|STATUS|STRIPED|SYSTEM_USER|TABLES?|TABLESPACE|TEMP(?:ORARY|TABLE)?|TERMINATED|TEXT(?:SIZE)?|THEN|TIME(?:STAMP)?|TINY(?:BLOB|INT|TEXT)|TOP?|TRAN(?:SACTIONS?)?|TRIGGER|TRUNCATE|TSEQUAL|TYPES?|UNBOUNDED|UNCOMMITTED|UNDEFINED|UNION|UNIQUE|UNLOCK|UNPIVOT|UNSIGNED|UPDATE(?:TEXT)?|USAGE|USE|USER|USING|VALUES?|VAR(?:BINARY|CHAR|CHARACTER|YING)|VIEW|WAITFOR|WARNINGS|WHEN|WHERE|WHILE|WITH(?: ROLLUP|IN)?|WORK|WRITE(?:TEXT)?|YEAR)\b/i,boolean:/\b(?:FALSE|NULL|TRUE)\b/i,number:/\b0x[\da-f]+\b|\b\d+(?:\.\d*)?|\B\.\d+\b/i,operator:/[-+*\/=%^~]|&&?|\|\|?|!=?|<(?:=>?|<|>)?|>[>=]?|\b(?:AND|BETWEEN|DIV|ILIKE|IN|IS|LIKE|NOT|OR|REGEXP|RLIKE|SOUNDS LIKE|XOR)\b/i,punctuation:/[;[\]()`,.]/},function(e){var t=e.languages.javascript["template-string"],n=t.pattern.source,a=t.inside.interpolation,r=a.inside["interpolation-punctuation"],o=a.pattern.source;function s(t,a){if(e.languages[t])return{pattern:RegExp("((?:"+a+")\\s*)"+n),lookbehind:!0,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},"embedded-code":{pattern:/[\s\S]+/,alias:t}}}}function i(e,t){return"___"+t.toUpperCase()+"_"+e+"___"}function l(t,n,a){var r={code:t,grammar:n,language:a};return e.hooks.run("before-tokenize",r),r.tokens=e.tokenize(r.code,r.grammar),e.hooks.run("after-tokenize",r),r.tokens}function c(t){var n={};n["interpolation-punctuation"]=r;var o=e.tokenize(t,n);if(3===o.length){var s=[1,1];s.push.apply(s,l(o[1],e.languages.javascript,"javascript")),o.splice.apply(o,s)}return new e.Token("interpolation",o,a.alias,t)}function u(t,n,a){var r=e.tokenize(t,{interpolation:{pattern:RegExp(o),lookbehind:!0}}),s=0,u={},d=l(r.map((function(e){if("string"==typeof e)return e;for(var n,r=e.content;-1!==t.indexOf(n=i(s++,a)););return u[n]=r,n})).join(""),n,a),f=Object.keys(u);return s=0,function e(t){for(var n=0;n<t.length;n++){if(s>=f.length)return;var a=t[n];if("string"==typeof a||"string"==typeof a.content){var r=f[s],o="string"==typeof a?a:a.content,i=o.indexOf(r);if(-1!==i){++s;var l=o.substring(0,i),d=c(u[r]),p=o.substring(i+r.length),m=[];if(l&&m.push(l),m.push(d),p){var g=[p];e(g),m.push.apply(m,g)}"string"==typeof a?(t.splice.apply(t,[n,1].concat(m)),n+=m.length-1):a.content=m}}else{var h=a.content;Array.isArray(h)?e(h):e([h])}}}(d),new e.Token(a,d,"language-"+a,t)}e.languages.javascript["template-string"]=[s("css",/\b(?:styled(?:\([^)]*\))?(?:\s*\.\s*\w+(?:\([^)]*\))*)*|css(?:\s*\.\s*(?:global|resolve))?|createGlobalStyle|keyframes)/.source),s("html",/\bhtml|\.\s*(?:inner|outer)HTML\s*\+?=/.source),s("svg",/\bsvg/.source),s("markdown",/\b(?:markdown|md)/.source),s("graphql",/\b(?:gql|graphql(?:\s*\.\s*experimental)?)/.source),s("sql",/\bsql/.source),t].filter(Boolean);var d={javascript:!0,js:!0,typescript:!0,ts:!0,jsx:!0,tsx:!0};function f(e){return"string"==typeof e?e:Array.isArray(e)?e.map(f).join(""):f(e.content)}e.hooks.add("after-tokenize",(function(t){t.language in d&&function t(n){for(var a=0,r=n.length;a<r;a++){var o=n[a];if("string"!=typeof o){var s=o.content;if(Array.isArray(s))if("template-string"===o.type){var i=s[1];if(3===s.length&&"string"!=typeof i&&"embedded-code"===i.type){var l=f(i),c=i.alias,d=Array.isArray(c)?c[0]:c,p=e.languages[d];if(!p)continue;s[1]=u(l,p,d)}}else t(s);else"string"!=typeof s&&t([s])}}}(t.tokens)}))}(r),function(e){e.languages.typescript=e.languages.extend("javascript",{"class-name":{pattern:/(\b(?:class|extends|implements|instanceof|interface|new|type)\s+)(?!keyof\b)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?:\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>)?/,lookbehind:!0,greedy:!0,inside:null},builtin:/\b(?:Array|Function|Promise|any|boolean|console|never|number|string|symbol|unknown)\b/}),e.languages.typescript.keyword.push(/\b(?:abstract|declare|is|keyof|readonly|require)\b/,/\b(?:asserts|infer|interface|module|namespace|type)\b(?=\s*(?:[{_$a-zA-Z\xA0-\uFFFF]|$))/,/\btype\b(?=\s*(?:[\{*]|$))/),delete e.languages.typescript.parameter,delete e.languages.typescript["literal-property"];var t=e.languages.extend("typescript",{});delete t["class-name"],e.languages.typescript["class-name"].inside=t,e.languages.insertBefore("typescript","function",{decorator:{pattern:/@[$\w\xA0-\uFFFF]+/,inside:{at:{pattern:/^@/,alias:"operator"},function:/^[\s\S]+/}},"generic-function":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>(?=\s*\()/,greedy:!0,inside:{function:/^#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*/,generic:{pattern:/<[\s\S]+/,alias:"class-name",inside:t}}}}),e.languages.ts=e.languages.typescript}(r),function(e){function t(e,t){return RegExp(e.replace(/<ID>/g,(function(){return/(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*/.source})),t)}e.languages.insertBefore("javascript","function-variable",{"method-variable":{pattern:RegExp("(\\.\\s*)"+e.languages.javascript["function-variable"].pattern.source),lookbehind:!0,alias:["function-variable","method","function","property-access"]}}),e.languages.insertBefore("javascript","function",{method:{pattern:RegExp("(\\.\\s*)"+e.languages.javascript.function.source),lookbehind:!0,alias:["function","property-access"]}}),e.languages.insertBefore("javascript","constant",{"known-class-name":[{pattern:/\b(?:(?:Float(?:32|64)|(?:Int|Uint)(?:8|16|32)|Uint8Clamped)?Array|ArrayBuffer|BigInt|Boolean|DataView|Date|Error|Function|Intl|JSON|(?:Weak)?(?:Map|Set)|Math|Number|Object|Promise|Proxy|Reflect|RegExp|String|Symbol|WebAssembly)\b/,alias:"class-name"},{pattern:/\b(?:[A-Z]\w*)Error\b/,alias:"class-name"}]}),e.languages.insertBefore("javascript","keyword",{imports:{pattern:t(/(\bimport\b\s*)(?:<ID>(?:\s*,\s*(?:\*\s*as\s+<ID>|\{[^{}]*\}))?|\*\s*as\s+<ID>|\{[^{}]*\})(?=\s*\bfrom\b)/.source),lookbehind:!0,inside:e.languages.javascript},exports:{pattern:t(/(\bexport\b\s*)(?:\*(?:\s*as\s+<ID>)?(?=\s*\bfrom\b)|\{[^{}]*\})/.source),lookbehind:!0,inside:e.languages.javascript}}),e.languages.javascript.keyword.unshift({pattern:/\b(?:as|default|export|from|import)\b/,alias:"module"},{pattern:/\b(?:await|break|catch|continue|do|else|finally|for|if|return|switch|throw|try|while|yield)\b/,alias:"control-flow"},{pattern:/\bnull\b/,alias:["null","nil"]},{pattern:/\bundefined\b/,alias:"nil"}),e.languages.insertBefore("javascript","operator",{spread:{pattern:/\.{3}/,alias:"operator"},arrow:{pattern:/=>/,alias:"operator"}}),e.languages.insertBefore("javascript","punctuation",{"property-access":{pattern:t(/(\.\s*)#?<ID>/.source),lookbehind:!0},"maybe-class-name":{pattern:/(^|[^$\w\xA0-\uFFFF])[A-Z][$\w\xA0-\uFFFF]+/,lookbehind:!0},dom:{pattern:/\b(?:document|(?:local|session)Storage|location|navigator|performance|window)\b/,alias:"variable"},console:{pattern:/\bconsole(?=\s*\.)/,alias:"class-name"}});for(var n=["function","function-variable","method","method-variable","property-access"],a=0;a<n.length;a++){var r=n[a],o=e.languages.javascript[r];"RegExp"===e.util.type(o)&&(o=e.languages.javascript[r]={pattern:o});var s=o.inside||{};o.inside=s,s["maybe-class-name"]=/^[A-Z][\s\S]*/}}(r),function(e){var t=e.util.clone(e.languages.javascript),n=/(?:\s|\/\/.*(?!.)|\/\*(?:[^*]|\*(?!\/))\*\/)/.source,a=/(?:\{(?:\{(?:\{[^{}]*\}|[^{}])*\}|[^{}])*\})/.source,r=/(?:\{<S>*\.{3}(?:[^{}]|<BRACES>)*\})/.source;function o(e,t){return e=e.replace(/<S>/g,(function(){return n})).replace(/<BRACES>/g,(function(){return a})).replace(/<SPREAD>/g,(function(){return r})),RegExp(e,t)}r=o(r).source,e.languages.jsx=e.languages.extend("markup",t),e.languages.jsx.tag.pattern=o(/<\/?(?:[\w.:-]+(?:<S>+(?:[\w.:$-]+(?:=(?:"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*'|[^\s{'"/>=]+|<BRACES>))?|<SPREAD>))*<S>*\/?)?>/.source),e.languages.jsx.tag.inside.tag.pattern=/^<\/?[^\s>\/]*/,e.languages.jsx.tag.inside["attr-value"].pattern=/=(?!\{)(?:"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*'|[^\s'">]+)/,e.languages.jsx.tag.inside.tag.inside["class-name"]=/^[A-Z]\w*(?:\.[A-Z]\w*)*$/,e.languages.jsx.tag.inside.comment=t.comment,e.languages.insertBefore("inside","attr-name",{spread:{pattern:o(/<SPREAD>/.source),inside:e.languages.jsx}},e.languages.jsx.tag),e.languages.insertBefore("inside","special-attr",{script:{pattern:o(/=<BRACES>/.source),alias:"language-javascript",inside:{"script-punctuation":{pattern:/^=(?=\{)/,alias:"punctuation"},rest:e.languages.jsx}}},e.languages.jsx.tag);var s=function(e){return e?"string"==typeof e?e:"string"==typeof e.content?e.content:e.content.map(s).join(""):""},i=function(t){for(var n=[],a=0;a<t.length;a++){var r=t[a],o=!1;if("string"!=typeof r&&("tag"===r.type&&r.content[0]&&"tag"===r.content[0].type?"</"===r.content[0].content[0].content?n.length>0&&n[n.length-1].tagName===s(r.content[0].content[1])&&n.pop():"/>"===r.content[r.content.length-1].content||n.push({tagName:s(r.content[0].content[1]),openedBraces:0}):n.length>0&&"punctuation"===r.type&&"{"===r.content?n[n.length-1].openedBraces++:n.length>0&&n[n.length-1].openedBraces>0&&"punctuation"===r.type&&"}"===r.content?n[n.length-1].openedBraces--:o=!0),(o||"string"==typeof r)&&n.length>0&&0===n[n.length-1].openedBraces){var l=s(r);a<t.length-1&&("string"==typeof t[a+1]||"plain-text"===t[a+1].type)&&(l+=s(t[a+1]),t.splice(a+1,1)),a>0&&("string"==typeof t[a-1]||"plain-text"===t[a-1].type)&&(l=s(t[a-1])+l,t.splice(a-1,1),a--),t[a]=new e.Token("plain-text",l,null,l)}r.content&&"string"!=typeof r.content&&i(r.content)}};e.hooks.add("after-tokenize",(function(e){"jsx"!==e.language&&"tsx"!==e.language||i(e.tokens)}))}(r),function(e){e.languages.diff={coord:[/^(?:\*{3}|-{3}|\+{3}).*$/m,/^@@.*@@$/m,/^\d.*$/m]};var t={"deleted-sign":"-","deleted-arrow":"<","inserted-sign":"+","inserted-arrow":">",unchanged:" ",diff:"!"};Object.keys(t).forEach((function(n){var a=t[n],r=[];/^\w+$/.test(n)||r.push(/\w+/.exec(n)[0]),"diff"===n&&r.push("bold"),e.languages.diff[n]={pattern:RegExp("^(?:["+a+"].*(?:\r\n?|\n|(?![\\s\\S])))+","m"),alias:r,inside:{line:{pattern:/(.)(?=[\s\S]).*(?:\r\n?|\n)?/,lookbehind:!0},prefix:{pattern:/[\s\S]/,alias:/\w+/.exec(n)[0]}}}})),Object.defineProperty(e.languages.diff,"PREFIXES",{value:t})}(r),r.languages.git={comment:/^#.*/m,deleted:/^[-\u2013].*/m,inserted:/^\+.*/m,string:/("|')(?:\\.|(?!\1)[^\\\r\n])*\1/,command:{pattern:/^.*\$ git .*$/m,inside:{parameter:/\s--?\w+/}},coord:/^@@.*@@$/m,"commit-sha1":/^commit \w{40}$/m},r.languages.go=r.languages.extend("clike",{string:{pattern:/(^|[^\\])"(?:\\.|[^"\\\r\n])*"|`[^`]*`/,lookbehind:!0,greedy:!0},keyword:/\b(?:break|case|chan|const|continue|default|defer|else|fallthrough|for|func|go(?:to)?|if|import|interface|map|package|range|return|select|struct|switch|type|var)\b/,boolean:/\b(?:_|false|iota|nil|true)\b/,number:[/\b0(?:b[01_]+|o[0-7_]+)i?\b/i,/\b0x(?:[a-f\d_]+(?:\.[a-f\d_]*)?|\.[a-f\d_]+)(?:p[+-]?\d+(?:_\d+)*)?i?(?!\w)/i,/(?:\b\d[\d_]*(?:\.[\d_]*)?|\B\.\d[\d_]*)(?:e[+-]?[\d_]+)?i?(?!\w)/i],operator:/[*\/%^!=]=?|\+[=+]?|-[=-]?|\|[=|]?|&(?:=|&|\^=?)?|>(?:>=?|=)?|<(?:<=?|=|-)?|:=|\.\.\./,builtin:/\b(?:append|bool|byte|cap|close|complex|complex(?:64|128)|copy|delete|error|float(?:32|64)|u?int(?:8|16|32|64)?|imag|len|make|new|panic|print(?:ln)?|real|recover|rune|string|uintptr)\b/}),r.languages.insertBefore("go","string",{char:{pattern:/'(?:\\.|[^'\\\r\n]){0,10}'/,greedy:!0}}),delete r.languages.go["class-name"],function(e){function t(e,t){return"___"+e.toUpperCase()+t+"___"}Object.defineProperties(e.languages["markup-templating"]={},{buildPlaceholders:{value:function(n,a,r,o){if(n.language===a){var s=n.tokenStack=[];n.code=n.code.replace(r,(function(e){if("function"==typeof o&&!o(e))return e;for(var r,i=s.length;-1!==n.code.indexOf(r=t(a,i));)++i;return s[i]=e,r})),n.grammar=e.languages.markup}}},tokenizePlaceholders:{value:function(n,a){if(n.language===a&&n.tokenStack){n.grammar=e.languages[a];var r=0,o=Object.keys(n.tokenStack);!function s(i){for(var l=0;l<i.length&&!(r>=o.length);l++){var c=i[l];if("string"==typeof c||c.content&&"string"==typeof c.content){var u=o[r],d=n.tokenStack[u],f="string"==typeof c?c:c.content,p=t(a,u),m=f.indexOf(p);if(m>-1){++r;var g=f.substring(0,m),h=new e.Token(a,e.tokenize(d,n.grammar),"language-"+a,d),b=f.substring(m+p.length),y=[];g&&y.push.apply(y,s([g])),y.push(h),b&&y.push.apply(y,s([b])),"string"==typeof c?i.splice.apply(i,[l,1].concat(y)):c.content=y}}else c.content&&s(c.content)}return i}(n.tokens)}}}})}(r),function(e){e.languages.handlebars={comment:/\{\{![\s\S]*?\}\}/,delimiter:{pattern:/^\{\{\{?|\}\}\}?$/,alias:"punctuation"},string:/(["'])(?:\\.|(?!\1)[^\\\r\n])*\1/,number:/\b0x[\dA-Fa-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[Ee][+-]?\d+)?/,boolean:/\b(?:false|true)\b/,block:{pattern:/^(\s*(?:~\s*)?)[#\/]\S+?(?=\s*(?:~\s*)?$|\s)/,lookbehind:!0,alias:"keyword"},brackets:{pattern:/\[[^\]]+\]/,inside:{punctuation:/\[|\]/,variable:/[\s\S]+/}},punctuation:/[!"#%&':()*+,.\/;<=>@\[\\\]^`{|}~]/,variable:/[^!"#%&'()*+,\/;<=>@\[\\\]^`{|}~\s]+/},e.hooks.add("before-tokenize",(function(t){e.languages["markup-templating"].buildPlaceholders(t,"handlebars",/\{\{\{[\s\S]+?\}\}\}|\{\{[\s\S]+?\}\}/g)})),e.hooks.add("after-tokenize",(function(t){e.languages["markup-templating"].tokenizePlaceholders(t,"handlebars")})),e.languages.hbs=e.languages.handlebars}(r),r.languages.json={property:{pattern:/(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?=\s*:)/,lookbehind:!0,greedy:!0},string:{pattern:/(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?!\s*:)/,lookbehind:!0,greedy:!0},comment:{pattern:/\/\/.*|\/\*[\s\S]*?(?:\*\/|$)/,greedy:!0},number:/-?\b\d+(?:\.\d+)?(?:e[+-]?\d+)?\b/i,punctuation:/[{}[\],]/,operator:/:/,boolean:/\b(?:false|true)\b/,null:{pattern:/\bnull\b/,alias:"keyword"}},r.languages.webmanifest=r.languages.json,r.languages.less=r.languages.extend("css",{comment:[/\/\*[\s\S]*?\*\//,{pattern:/(^|[^\\])\/\/.*/,lookbehind:!0}],atrule:{pattern:/@[\w-](?:\((?:[^(){}]|\([^(){}]*\))*\)|[^(){};\s]|\s+(?!\s))*?(?=\s*\{)/,inside:{punctuation:/[:()]/}},selector:{pattern:/(?:@\{[\w-]+\}|[^{};\s@])(?:@\{[\w-]+\}|\((?:[^(){}]|\([^(){}]*\))*\)|[^(){};@\s]|\s+(?!\s))*?(?=\s*\{)/,inside:{variable:/@+[\w-]+/}},property:/(?:@\{[\w-]+\}|[\w-])+(?:\+_?)?(?=\s*:)/,operator:/[+\-*\/]/}),r.languages.insertBefore("less","property",{variable:[{pattern:/@[\w-]+\s*:/,inside:{punctuation:/:/}},/@@?[\w-]+/],"mixin-usage":{pattern:/([{;]\s*)[.#](?!\d)[\w-].*?(?=[(;])/,lookbehind:!0,alias:"function"}}),r.languages.makefile={comment:{pattern:/(^|[^\\])#(?:\\(?:\r\n|[\s\S])|[^\\\r\n])*/,lookbehind:!0},string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"builtin-target":{pattern:/\.[A-Z][^:#=\s]+(?=\s*:(?!=))/,alias:"builtin"},target:{pattern:/^(?:[^:=\s]|[ \t]+(?![\s:]))+(?=\s*:(?!=))/m,alias:"symbol",inside:{variable:/\$+(?:(?!\$)[^(){}:#=\s]+|(?=[({]))/}},variable:/\$+(?:(?!\$)[^(){}:#=\s]+|\([@*%<^+?][DF]\)|(?=[({]))/,keyword:/-include\b|\b(?:define|else|endef|endif|export|ifn?def|ifn?eq|include|override|private|sinclude|undefine|unexport|vpath)\b/,function:{pattern:/(\()(?:abspath|addsuffix|and|basename|call|dir|error|eval|file|filter(?:-out)?|findstring|firstword|flavor|foreach|guile|if|info|join|lastword|load|notdir|or|origin|patsubst|realpath|shell|sort|strip|subst|suffix|value|warning|wildcard|word(?:list|s)?)(?=[ \t])/,lookbehind:!0},operator:/(?:::|[?:+!])?=|[|@]/,punctuation:/[:;(){}]/},r.languages.objectivec=r.languages.extend("c",{string:{pattern:/@?"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"/,greedy:!0},keyword:/\b(?:asm|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|in|inline|int|long|register|return|self|short|signed|sizeof|static|struct|super|switch|typedef|typeof|union|unsigned|void|volatile|while)\b|(?:@interface|@end|@implementation|@protocol|@class|@public|@protected|@private|@property|@try|@catch|@finally|@throw|@synthesize|@dynamic|@selector)\b/,operator:/-[->]?|\+\+?|!=?|<<?=?|>>?=?|==?|&&?|\|\|?|[~^%?*\/@]/}),delete r.languages.objectivec["class-name"],r.languages.objc=r.languages.objectivec,r.languages.ocaml={comment:{pattern:/\(\*[\s\S]*?\*\)/,greedy:!0},char:{pattern:/'(?:[^\\\r\n']|\\(?:.|[ox]?[0-9a-f]{1,3}))'/i,greedy:!0},string:[{pattern:/"(?:\\(?:[\s\S]|\r\n)|[^\\\r\n"])*"/,greedy:!0},{pattern:/\{([a-z_]*)\|[\s\S]*?\|\1\}/,greedy:!0}],number:[/\b(?:0b[01][01_]*|0o[0-7][0-7_]*)\b/i,/\b0x[a-f0-9][a-f0-9_]*(?:\.[a-f0-9_]*)?(?:p[+-]?\d[\d_]*)?(?!\w)/i,/\b\d[\d_]*(?:\.[\d_]*)?(?:e[+-]?\d[\d_]*)?(?!\w)/i],directive:{pattern:/\B#\w+/,alias:"property"},label:{pattern:/\B~\w+/,alias:"property"},"type-variable":{pattern:/\B'\w+/,alias:"function"},variant:{pattern:/`\w+/,alias:"symbol"},keyword:/\b(?:as|assert|begin|class|constraint|do|done|downto|else|end|exception|external|for|fun|function|functor|if|in|include|inherit|initializer|lazy|let|match|method|module|mutable|new|nonrec|object|of|open|private|rec|sig|struct|then|to|try|type|val|value|virtual|when|where|while|with)\b/,boolean:/\b(?:false|true)\b/,"operator-like-punctuation":{pattern:/\[[<>|]|[>|]\]|\{<|>\}/,alias:"punctuation"},operator:/\.[.~]|:[=>]|[=<>@^|&+\-*\/$%!?~][!$%&*+\-.\/:<=>?@^|~]*|\b(?:and|asr|land|lor|lsl|lsr|lxor|mod|or)\b/,punctuation:/;;|::|[(){}\[\].,:;#]|\b_\b/},r.languages.python={comment:{pattern:/(^|[^\\])#.*/,lookbehind:!0,greedy:!0},"string-interpolation":{pattern:/(?:f|fr|rf)(?:("""|''')[\s\S]*?\1|("|')(?:\\.|(?!\2)[^\\\r\n])*\2)/i,greedy:!0,inside:{interpolation:{pattern:/((?:^|[^{])(?:\{\{)*)\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}])+\})+\})+\}/,lookbehind:!0,inside:{"format-spec":{pattern:/(:)[^:(){}]+(?=\}$)/,lookbehind:!0},"conversion-option":{pattern:/![sra](?=[:}]$)/,alias:"punctuation"},rest:null}},string:/[\s\S]+/}},"triple-quoted-string":{pattern:/(?:[rub]|br|rb)?("""|''')[\s\S]*?\1/i,greedy:!0,alias:"string"},string:{pattern:/(?:[rub]|br|rb)?("|')(?:\\.|(?!\1)[^\\\r\n])*\1/i,greedy:!0},function:{pattern:/((?:^|\s)def[ \t]+)[a-zA-Z_]\w*(?=\s*\()/g,lookbehind:!0},"class-name":{pattern:/(\bclass\s+)\w+/i,lookbehind:!0},decorator:{pattern:/(^[\t ]*)@\w+(?:\.\w+)*/m,lookbehind:!0,alias:["annotation","punctuation"],inside:{punctuation:/\./}},keyword:/\b(?:_(?=\s*:)|and|as|assert|async|await|break|case|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|match|nonlocal|not|or|pass|print|raise|return|try|while|with|yield)\b/,builtin:/\b(?:__import__|abs|all|any|apply|ascii|basestring|bin|bool|buffer|bytearray|bytes|callable|chr|classmethod|cmp|coerce|compile|complex|delattr|dict|dir|divmod|enumerate|eval|execfile|file|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|intern|isinstance|issubclass|iter|len|list|locals|long|map|max|memoryview|min|next|object|oct|open|ord|pow|property|range|raw_input|reduce|reload|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|unichr|unicode|vars|xrange|zip)\b/,boolean:/\b(?:False|None|True)\b/,number:/\b0(?:b(?:_?[01])+|o(?:_?[0-7])+|x(?:_?[a-f0-9])+)\b|(?:\b\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\B\.\d+(?:_\d+)*)(?:e[+-]?\d+(?:_\d+)*)?j?(?!\w)/i,operator:/[-+%=]=?|!=|:=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]/,punctuation:/[{}[\];(),.:]/},r.languages.python["string-interpolation"].inside.interpolation.inside.rest=r.languages.python,r.languages.py=r.languages.python,r.languages.reason=r.languages.extend("clike",{string:{pattern:/"(?:\\(?:\r\n|[\s\S])|[^\\\r\n"])*"/,greedy:!0},"class-name":/\b[A-Z]\w*/,keyword:/\b(?:and|as|assert|begin|class|constraint|do|done|downto|else|end|exception|external|for|fun|function|functor|if|in|include|inherit|initializer|lazy|let|method|module|mutable|new|nonrec|object|of|open|or|private|rec|sig|struct|switch|then|to|try|type|val|virtual|when|while|with)\b/,operator:/\.{3}|:[:=]|\|>|->|=(?:==?|>)?|<=?|>=?|[|^?'#!~`]|[+\-*\/]\.?|\b(?:asr|land|lor|lsl|lsr|lxor|mod)\b/}),r.languages.insertBefore("reason","class-name",{char:{pattern:/'(?:\\x[\da-f]{2}|\\o[0-3][0-7][0-7]|\\\d{3}|\\.|[^'\\\r\n])'/,greedy:!0},constructor:/\b[A-Z]\w*\b(?!\s*\.)/,label:{pattern:/\b[a-z]\w*(?=::)/,alias:"symbol"}}),delete r.languages.reason.function,function(e){e.languages.sass=e.languages.extend("css",{comment:{pattern:/^([ \t]*)\/[\/*].*(?:(?:\r?\n|\r)\1[ \t].+)*/m,lookbehind:!0,greedy:!0}}),e.languages.insertBefore("sass","atrule",{"atrule-line":{pattern:/^(?:[ \t]*)[@+=].+/m,greedy:!0,inside:{atrule:/(?:@[\w-]+|[+=])/}}}),delete e.languages.sass.atrule;var t=/\$[-\w]+|#\{\$[-\w]+\}/,n=[/[+*\/%]|[=!]=|<=?|>=?|\b(?:and|not|or)\b/,{pattern:/(\s)-(?=\s)/,lookbehind:!0}];e.languages.insertBefore("sass","property",{"variable-line":{pattern:/^[ \t]*\$.+/m,greedy:!0,inside:{punctuation:/:/,variable:t,operator:n}},"property-line":{pattern:/^[ \t]*(?:[^:\s]+ *:.*|:[^:\s].*)/m,greedy:!0,inside:{property:[/[^:\s]+(?=\s*:)/,{pattern:/(:)[^:\s]+/,lookbehind:!0}],punctuation:/:/,variable:t,operator:n,important:e.languages.sass.important}}}),delete e.languages.sass.property,delete e.languages.sass.important,e.languages.insertBefore("sass","punctuation",{selector:{pattern:/^([ \t]*)\S(?:,[^,\r\n]+|[^,\r\n]*)(?:,[^,\r\n]+)*(?:,(?:\r?\n|\r)\1[ \t]+\S(?:,[^,\r\n]+|[^,\r\n]*)(?:,[^,\r\n]+)*)*/m,lookbehind:!0,greedy:!0}})}(r),r.languages.scss=r.languages.extend("css",{comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|\/\/.*)/,lookbehind:!0},atrule:{pattern:/@[\w-](?:\([^()]+\)|[^()\s]|\s+(?!\s))*?(?=\s+[{;])/,inside:{rule:/@[\w-]+/}},url:/(?:[-a-z]+-)?url(?=\()/i,selector:{pattern:/(?=\S)[^@;{}()]?(?:[^@;{}()\s]|\s+(?!\s)|#\{\$[-\w]+\})+(?=\s*\{(?:\}|\s|[^}][^:{}]*[:{][^}]))/,inside:{parent:{pattern:/&/,alias:"important"},placeholder:/%[-\w]+/,variable:/\$[-\w]+|#\{\$[-\w]+\}/}},property:{pattern:/(?:[-\w]|\$[-\w]|#\{\$[-\w]+\})+(?=\s*:)/,inside:{variable:/\$[-\w]+|#\{\$[-\w]+\}/}}}),r.languages.insertBefore("scss","atrule",{keyword:[/@(?:content|debug|each|else(?: if)?|extend|for|forward|function|if|import|include|mixin|return|use|warn|while)\b/i,{pattern:/( )(?:from|through)(?= )/,lookbehind:!0}]}),r.languages.insertBefore("scss","important",{variable:/\$[-\w]+|#\{\$[-\w]+\}/}),r.languages.insertBefore("scss","function",{"module-modifier":{pattern:/\b(?:as|hide|show|with)\b/i,alias:"keyword"},placeholder:{pattern:/%[-\w]+/,alias:"selector"},statement:{pattern:/\B!(?:default|optional)\b/i,alias:"keyword"},boolean:/\b(?:false|true)\b/,null:{pattern:/\bnull\b/,alias:"keyword"},operator:{pattern:/(\s)(?:[-+*\/%]|[=!]=|<=?|>=?|and|not|or)(?=\s)/,lookbehind:!0}}),r.languages.scss.atrule.inside.rest=r.languages.scss,function(e){var t={pattern:/(\b\d+)(?:%|[a-z]+)/,lookbehind:!0},n={pattern:/(^|[^\w.-])-?(?:\d+(?:\.\d+)?|\.\d+)/,lookbehind:!0},a={comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|\/\/.*)/,lookbehind:!0},url:{pattern:/\burl\((["']?).*?\1\)/i,greedy:!0},string:{pattern:/("|')(?:(?!\1)[^\\\r\n]|\\(?:\r\n|[\s\S]))*\1/,greedy:!0},interpolation:null,func:null,important:/\B!(?:important|optional)\b/i,keyword:{pattern:/(^|\s+)(?:(?:else|for|if|return|unless)(?=\s|$)|@[\w-]+)/,lookbehind:!0},hexcode:/#[\da-f]{3,6}/i,color:[/\b(?:AliceBlue|AntiqueWhite|Aqua|Aquamarine|Azure|Beige|Bisque|Black|BlanchedAlmond|Blue|BlueViolet|Brown|BurlyWood|CadetBlue|Chartreuse|Chocolate|Coral|CornflowerBlue|Cornsilk|Crimson|Cyan|DarkBlue|DarkCyan|DarkGoldenRod|DarkGr[ae]y|DarkGreen|DarkKhaki|DarkMagenta|DarkOliveGreen|DarkOrange|DarkOrchid|DarkRed|DarkSalmon|DarkSeaGreen|DarkSlateBlue|DarkSlateGr[ae]y|DarkTurquoise|DarkViolet|DeepPink|DeepSkyBlue|DimGr[ae]y|DodgerBlue|FireBrick|FloralWhite|ForestGreen|Fuchsia|Gainsboro|GhostWhite|Gold|GoldenRod|Gr[ae]y|Green|GreenYellow|HoneyDew|HotPink|IndianRed|Indigo|Ivory|Khaki|Lavender|LavenderBlush|LawnGreen|LemonChiffon|LightBlue|LightCoral|LightCyan|LightGoldenRodYellow|LightGr[ae]y|LightGreen|LightPink|LightSalmon|LightSeaGreen|LightSkyBlue|LightSlateGr[ae]y|LightSteelBlue|LightYellow|Lime|LimeGreen|Linen|Magenta|Maroon|MediumAquaMarine|MediumBlue|MediumOrchid|MediumPurple|MediumSeaGreen|MediumSlateBlue|MediumSpringGreen|MediumTurquoise|MediumVioletRed|MidnightBlue|MintCream|MistyRose|Moccasin|NavajoWhite|Navy|OldLace|Olive|OliveDrab|Orange|OrangeRed|Orchid|PaleGoldenRod|PaleGreen|PaleTurquoise|PaleVioletRed|PapayaWhip|PeachPuff|Peru|Pink|Plum|PowderBlue|Purple|Red|RosyBrown|RoyalBlue|SaddleBrown|Salmon|SandyBrown|SeaGreen|SeaShell|Sienna|Silver|SkyBlue|SlateBlue|SlateGr[ae]y|Snow|SpringGreen|SteelBlue|Tan|Teal|Thistle|Tomato|Transparent|Turquoise|Violet|Wheat|White|WhiteSmoke|Yellow|YellowGreen)\b/i,{pattern:/\b(?:hsl|rgb)\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*\)\B|\b(?:hsl|rgb)a\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*,\s*(?:0|0?\.\d+|1)\s*\)\B/i,inside:{unit:t,number:n,function:/[\w-]+(?=\()/,punctuation:/[(),]/}}],entity:/\\[\da-f]{1,8}/i,unit:t,boolean:/\b(?:false|true)\b/,operator:[/~|[+!\/%<>?=]=?|[-:]=|\*[*=]?|\.{2,3}|&&|\|\||\B-\B|\b(?:and|in|is(?: a| defined| not|nt)?|not|or)\b/],number:n,punctuation:/[{}()\[\];:,]/};a.interpolation={pattern:/\{[^\r\n}:]+\}/,alias:"variable",inside:{delimiter:{pattern:/^\{|\}$/,alias:"punctuation"},rest:a}},a.func={pattern:/[\w-]+\([^)]*\).*/,inside:{function:/^[^(]+/,rest:a}},e.languages.stylus={"atrule-declaration":{pattern:/(^[ \t]*)@.+/m,lookbehind:!0,inside:{atrule:/^@[\w-]+/,rest:a}},"variable-declaration":{pattern:/(^[ \t]*)[\w$-]+\s*.?=[ \t]*(?:\{[^{}]*\}|\S.*|$)/m,lookbehind:!0,inside:{variable:/^\S+/,rest:a}},statement:{pattern:/(^[ \t]*)(?:else|for|if|return|unless)[ \t].+/m,lookbehind:!0,inside:{keyword:/^\S+/,rest:a}},"property-declaration":{pattern:/((?:^|\{)([ \t]*))(?:[\w-]|\{[^}\r\n]+\})+(?:\s*:\s*|[ \t]+)(?!\s)[^{\r\n]*(?:;|[^{\r\n,]$(?!(?:\r?\n|\r)(?:\{|\2[ \t])))/m,lookbehind:!0,inside:{property:{pattern:/^[^\s:]+/,inside:{interpolation:a.interpolation}},rest:a}},selector:{pattern:/(^[ \t]*)(?:(?=\S)(?:[^{}\r\n:()]|::?[\w-]+(?:\([^)\r\n]*\)|(?![\w-]))|\{[^}\r\n]+\})+)(?:(?:\r?\n|\r)(?:\1(?:(?=\S)(?:[^{}\r\n:()]|::?[\w-]+(?:\([^)\r\n]*\)|(?![\w-]))|\{[^}\r\n]+\})+)))*(?:,$|\{|(?=(?:\r?\n|\r)(?:\{|\1[ \t])))/m,lookbehind:!0,inside:{interpolation:a.interpolation,comment:a.comment,punctuation:/[{},]/}},func:a.func,string:a.string,comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|\/\/.*)/,lookbehind:!0,greedy:!0},interpolation:a.interpolation,punctuation:/[{}()\[\];:.]/}}(r),function(e){var t=e.util.clone(e.languages.typescript);e.languages.tsx=e.languages.extend("jsx",t),delete e.languages.tsx.parameter,delete e.languages.tsx["literal-property"];var n=e.languages.tsx.tag;n.pattern=RegExp(/(^|[^\w$]|(?=<\/))/.source+"(?:"+n.pattern.source+")",n.pattern.flags),n.lookbehind=!0}(r),r.languages.wasm={comment:[/\(;[\s\S]*?;\)/,{pattern:/;;.*/,greedy:!0}],string:{pattern:/"(?:\\[\s\S]|[^"\\])*"/,greedy:!0},keyword:[{pattern:/\b(?:align|offset)=/,inside:{operator:/=/}},{pattern:/\b(?:(?:f32|f64|i32|i64)(?:\.(?:abs|add|and|ceil|clz|const|convert_[su]\/i(?:32|64)|copysign|ctz|demote\/f64|div(?:_[su])?|eqz?|extend_[su]\/i32|floor|ge(?:_[su])?|gt(?:_[su])?|le(?:_[su])?|load(?:(?:8|16|32)_[su])?|lt(?:_[su])?|max|min|mul|neg?|nearest|or|popcnt|promote\/f32|reinterpret\/[fi](?:32|64)|rem_[su]|rot[lr]|shl|shr_[su]|sqrt|store(?:8|16|32)?|sub|trunc(?:_[su]\/f(?:32|64))?|wrap\/i64|xor))?|memory\.(?:grow|size))\b/,inside:{punctuation:/\./}},/\b(?:anyfunc|block|br(?:_if|_table)?|call(?:_indirect)?|data|drop|elem|else|end|export|func|get_(?:global|local)|global|if|import|local|loop|memory|module|mut|nop|offset|param|result|return|select|set_(?:global|local)|start|table|tee_local|then|type|unreachable)\b/],variable:/\$[\w!#$%&'*+\-./:<=>?@\\^`|~]+/,number:/[+-]?\b(?:\d(?:_?\d)*(?:\.\d(?:_?\d)*)?(?:[eE][+-]?\d(?:_?\d)*)?|0x[\da-fA-F](?:_?[\da-fA-F])*(?:\.[\da-fA-F](?:_?[\da-fA-D])*)?(?:[pP][+-]?\d(?:_?\d)*)?)\b|\binf\b|\bnan(?::0x[\da-fA-F](?:_?[\da-fA-D])*)?\b/,punctuation:/[()]/};const o=r},5342:()=>{!function(e){for(var t=/\/\*(?:[^*/]|\*(?!\/)|\/(?!\*)|<self>)*\*\//.source,n=0;n<2;n++)t=t.replace(/<self>/g,(function(){return t}));t=t.replace(/<self>/g,(function(){return/[^\s\S]/.source})),e.languages.rust={comment:[{pattern:RegExp(/(^|[^\\])/.source+t),lookbehind:!0,greedy:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/b?"(?:\\[\s\S]|[^\\"])*"|b?r(#*)"(?:[^"]|"(?!\1))*"\1/,greedy:!0},char:{pattern:/b?'(?:\\(?:x[0-7][\da-fA-F]|u\{(?:[\da-fA-F]_*){1,6}\}|.)|[^\\\r\n\t'])'/,greedy:!0},attribute:{pattern:/#!?\[(?:[^\[\]"]|"(?:\\[\s\S]|[^\\"])*")*\]/,greedy:!0,alias:"attr-name",inside:{string:null}},"closure-params":{pattern:/([=(,:]\s*|\bmove\s*)\|[^|]*\||\|[^|]*\|(?=\s*(?:\{|->))/,lookbehind:!0,greedy:!0,inside:{"closure-punctuation":{pattern:/^\||\|$/,alias:"punctuation"},rest:null}},"lifetime-annotation":{pattern:/'\w+/,alias:"symbol"},"fragment-specifier":{pattern:/(\$\w+:)[a-z]+/,lookbehind:!0,alias:"punctuation"},variable:/\$\w+/,"function-definition":{pattern:/(\bfn\s+)\w+/,lookbehind:!0,alias:"function"},"type-definition":{pattern:/(\b(?:enum|struct|trait|type|union)\s+)\w+/,lookbehind:!0,alias:"class-name"},"module-declaration":[{pattern:/(\b(?:crate|mod)\s+)[a-z][a-z_\d]*/,lookbehind:!0,alias:"namespace"},{pattern:/(\b(?:crate|self|super)\s*)::\s*[a-z][a-z_\d]*\b(?:\s*::(?:\s*[a-z][a-z_\d]*\s*::)*)?/,lookbehind:!0,alias:"namespace",inside:{punctuation:/::/}}],keyword:[/\b(?:Self|abstract|as|async|await|become|box|break|const|continue|crate|do|dyn|else|enum|extern|final|fn|for|if|impl|in|let|loop|macro|match|mod|move|mut|override|priv|pub|ref|return|self|static|struct|super|trait|try|type|typeof|union|unsafe|unsized|use|virtual|where|while|yield)\b/,/\b(?:bool|char|f(?:32|64)|[ui](?:8|16|32|64|128|size)|str)\b/],function:/\b[a-z_]\w*(?=\s*(?:::\s*<|\())/,macro:{pattern:/\b\w+!/,alias:"property"},constant:/\b[A-Z_][A-Z_\d]+\b/,"class-name":/\b[A-Z]\w*\b/,namespace:{pattern:/(?:\b[a-z][a-z_\d]*\s*::\s*)*\b[a-z][a-z_\d]*\s*::(?!\s*<)/,inside:{punctuation:/::/}},number:/\b(?:0x[\dA-Fa-f](?:_?[\dA-Fa-f])*|0o[0-7](?:_?[0-7])*|0b[01](?:_?[01])*|(?:(?:\d(?:_?\d)*)?\.)?\d(?:_?\d)*(?:[Ee][+-]?\d+)?)(?:_?(?:f32|f64|[iu](?:8|16|32|64|size)?))?\b/,boolean:/\b(?:false|true)\b/,punctuation:/->|\.\.=|\.{1,3}|::|[{}[\];(),:]/,operator:/[-+*\/%!^]=?|=[=>]?|&[&=]?|\|[|=]?|<<?=?|>>?=?|[@?]/},e.languages.rust["closure-params"].inside.rest=e.languages.rust,e.languages.rust.attribute.inside.string=e.languages.rust.string}(Prism)},132:()=>{!function(e){var t=/(?:[\w-]+|'[^'\n\r]*'|"(?:\\.|[^\\"\r\n])*")/.source;function n(e){return e.replace(/__/g,(function(){return t}))}e.languages.toml={comment:{pattern:/#.*/,greedy:!0},table:{pattern:RegExp(n(/(^[\t ]*\[\s*(?:\[\s*)?)__(?:\s*\.\s*__)*(?=\s*\])/.source),"m"),lookbehind:!0,greedy:!0,alias:"class-name"},key:{pattern:RegExp(n(/(^[\t ]*|[{,]\s*)__(?:\s*\.\s*__)*(?=\s*=)/.source),"m"),lookbehind:!0,greedy:!0,alias:"property"},string:{pattern:/"""(?:\\[\s\S]|[^\\])*?"""|'''[\s\S]*?'''|'[^'\n\r]*'|"(?:\\.|[^\\"\r\n])*"/,greedy:!0},date:[{pattern:/\b\d{4}-\d{2}-\d{2}(?:[T\s]\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})?)?\b/i,alias:"number"},{pattern:/\b\d{2}:\d{2}:\d{2}(?:\.\d+)?\b/,alias:"number"}],number:/(?:\b0(?:x[\da-zA-Z]+(?:_[\da-zA-Z]+)*|o[0-7]+(?:_[0-7]+)*|b[10]+(?:_[10]+)*))\b|[-+]?\b\d+(?:_\d+)*(?:\.\d+(?:_\d+)*)?(?:[eE][+-]?\d+(?:_\d+)*)?\b|[-+]?\b(?:inf|nan)\b/,boolean:/\b(?:false|true)\b/,punctuation:/[.,=[\]{}]/}}(Prism)},3319:(e,t,n)=>{var a={"./prism-rust":5342,"./prism-toml":132};function r(e){var t=o(e);return n(t)}function o(e){if(!n.o(a,e)){var t=new Error("Cannot find module '"+e+"'");throw t.code="MODULE_NOT_FOUND",t}return a[e]}r.keys=function(){return Object.keys(a)},r.resolve=o,e.exports=r,r.id=3319},2694:(e,t,n)=>{"use strict";var a=n(6925);function r(){}function o(){}o.resetWarningCache=r,e.exports=function(){function e(e,t,n,r,o,s){if(s!==a){var i=new Error("Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types");throw i.name="Invariant Violation",i}}function t(){return e}e.isRequired=e;var n={array:e,bigint:e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:t,element:e,elementType:e,instanceOf:t,node:e,objectOf:t,oneOf:t,oneOfType:t,shape:t,exact:t,checkPropTypes:o,resetWarningCache:r};return n.PropTypes=n,n}},5556:(e,t,n)=>{e.exports=n(2694)()},6925:e=>{"use strict";e.exports="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"},2551:(e,t,n)=>{"use strict";var a=n(6540),r=n(5228),o=n(9982);function s(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n<arguments.length;n++)t+="&args[]="+encodeURIComponent(arguments[n]);return"Minified React error #"+e+"; visit "+t+" for the full message or use the non-minified dev environment for full errors and additional helpful warnings."}if(!a)throw Error(s(227));var i=new Set,l={};function c(e,t){u(e,t),u(e+"Capture",t)}function u(e,t){for(l[e]=t,e=0;e<t.length;e++)i.add(t[e])}var d=!("undefined"==typeof window||void 0===window.document||void 0===window.document.createElement),f=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,p=Object.prototype.hasOwnProperty,m={},g={};function h(e,t,n,a,r,o,s){this.acceptsBooleans=2===t||3===t||4===t,this.attributeName=a,this.attributeNamespace=r,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=o,this.removeEmptyString=s}var b={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach((function(e){b[e]=new h(e,0,!1,e,null,!1,!1)})),[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach((function(e){var t=e[0];b[t]=new h(t,1,!1,e[1],null,!1,!1)})),["contentEditable","draggable","spellCheck","value"].forEach((function(e){b[e]=new h(e,2,!1,e.toLowerCase(),null,!1,!1)})),["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach((function(e){b[e]=new h(e,2,!1,e,null,!1,!1)})),"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach((function(e){b[e]=new h(e,3,!1,e.toLowerCase(),null,!1,!1)})),["checked","multiple","muted","selected"].forEach((function(e){b[e]=new h(e,3,!0,e,null,!1,!1)})),["capture","download"].forEach((function(e){b[e]=new h(e,4,!1,e,null,!1,!1)})),["cols","rows","size","span"].forEach((function(e){b[e]=new h(e,6,!1,e,null,!1,!1)})),["rowSpan","start"].forEach((function(e){b[e]=new h(e,5,!1,e.toLowerCase(),null,!1,!1)}));var y=/[\-:]([a-z])/g;function v(e){return e[1].toUpperCase()}function x(e,t,n,a){var r=b.hasOwnProperty(t)?b[t]:null;(null!==r?0===r.type:!a&&(2<t.length&&("o"===t[0]||"O"===t[0])&&("n"===t[1]||"N"===t[1])))||(function(e,t,n,a){if(null==t||function(e,t,n,a){if(null!==n&&0===n.type)return!1;switch(typeof t){case"function":case"symbol":return!0;case"boolean":return!a&&(null!==n?!n.acceptsBooleans:"data-"!==(e=e.toLowerCase().slice(0,5))&&"aria-"!==e);default:return!1}}(e,t,n,a))return!0;if(a)return!1;if(null!==n)switch(n.type){case 3:return!t;case 4:return!1===t;case 5:return isNaN(t);case 6:return isNaN(t)||1>t}return!1}(t,n,r,a)&&(n=null),a||null===r?function(e){return!!p.call(g,e)||!p.call(m,e)&&(f.test(e)?g[e]=!0:(m[e]=!0,!1))}(t)&&(null===n?e.removeAttribute(t):e.setAttribute(t,""+n)):r.mustUseProperty?e[r.propertyName]=null===n?3!==r.type&&"":n:(t=r.attributeName,a=r.attributeNamespace,null===n?e.removeAttribute(t):(n=3===(r=r.type)||4===r&&!0===n?"":""+n,a?e.setAttributeNS(a,t,n):e.setAttribute(t,n))))}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach((function(e){var t=e.replace(y,v);b[t]=new h(t,1,!1,e,null,!1,!1)})),"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach((function(e){var t=e.replace(y,v);b[t]=new h(t,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)})),["xml:base","xml:lang","xml:space"].forEach((function(e){var t=e.replace(y,v);b[t]=new h(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)})),["tabIndex","crossOrigin"].forEach((function(e){b[e]=new h(e,1,!1,e.toLowerCase(),null,!1,!1)})),b.xlinkHref=new h("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1),["src","href","action","formAction"].forEach((function(e){b[e]=new h(e,1,!1,e.toLowerCase(),null,!0,!0)}));var w=a.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,S=60103,E=60106,k=60107,_=60108,A=60114,C=60109,q=60110,T=60112,N=60113,L=60120,O=60115,P=60116,R=60121,I=60128,M=60129,D=60130,F=60131;if("function"==typeof Symbol&&Symbol.for){var B=Symbol.for;S=B("react.element"),E=B("react.portal"),k=B("react.fragment"),_=B("react.strict_mode"),A=B("react.profiler"),C=B("react.provider"),q=B("react.context"),T=B("react.forward_ref"),N=B("react.suspense"),L=B("react.suspense_list"),O=B("react.memo"),P=B("react.lazy"),R=B("react.block"),B("react.scope"),I=B("react.opaque.id"),M=B("react.debug_trace_mode"),D=B("react.offscreen"),F=B("react.legacy_hidden")}var j,z="function"==typeof Symbol&&Symbol.iterator;function $(e){return null===e||"object"!=typeof e?null:"function"==typeof(e=z&&e[z]||e["@@iterator"])?e:null}function U(e){if(void 0===j)try{throw Error()}catch(n){var t=n.stack.trim().match(/\n( *(at )?)/);j=t&&t[1]||""}return"\n"+j+e}var H=!1;function V(e,t){if(!e||H)return"";H=!0;var n=Error.prepareStackTrace;Error.prepareStackTrace=void 0;try{if(t)if(t=function(){throw Error()},Object.defineProperty(t.prototype,"props",{set:function(){throw Error()}}),"object"==typeof Reflect&&Reflect.construct){try{Reflect.construct(t,[])}catch(l){var a=l}Reflect.construct(e,[],t)}else{try{t.call()}catch(l){a=l}e.call(t.prototype)}else{try{throw Error()}catch(l){a=l}e()}}catch(l){if(l&&a&&"string"==typeof l.stack){for(var r=l.stack.split("\n"),o=a.stack.split("\n"),s=r.length-1,i=o.length-1;1<=s&&0<=i&&r[s]!==o[i];)i--;for(;1<=s&&0<=i;s--,i--)if(r[s]!==o[i]){if(1!==s||1!==i)do{if(s--,0>--i||r[s]!==o[i])return"\n"+r[s].replace(" at new "," at ")}while(1<=s&&0<=i);break}}}finally{H=!1,Error.prepareStackTrace=n}return(e=e?e.displayName||e.name:"")?U(e):""}function G(e){switch(e.tag){case 5:return U(e.type);case 16:return U("Lazy");case 13:return U("Suspense");case 19:return U("SuspenseList");case 0:case 2:case 15:return e=V(e.type,!1);case 11:return e=V(e.type.render,!1);case 22:return e=V(e.type._render,!1);case 1:return e=V(e.type,!0);default:return""}}function W(e){if(null==e)return null;if("function"==typeof e)return e.displayName||e.name||null;if("string"==typeof e)return e;switch(e){case k:return"Fragment";case E:return"Portal";case A:return"Profiler";case _:return"StrictMode";case N:return"Suspense";case L:return"SuspenseList"}if("object"==typeof e)switch(e.$$typeof){case q:return(e.displayName||"Context")+".Consumer";case C:return(e._context.displayName||"Context")+".Provider";case T:var t=e.render;return t=t.displayName||t.name||"",e.displayName||(""!==t?"ForwardRef("+t+")":"ForwardRef");case O:return W(e.type);case R:return W(e._render);case P:t=e._payload,e=e._init;try{return W(e(t))}catch(n){}}return null}function Y(e){switch(typeof e){case"boolean":case"number":case"object":case"string":case"undefined":return e;default:return""}}function K(e){var t=e.type;return(e=e.nodeName)&&"input"===e.toLowerCase()&&("checkbox"===t||"radio"===t)}function Q(e){e._valueTracker||(e._valueTracker=function(e){var t=K(e)?"checked":"value",n=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),a=""+e[t];if(!e.hasOwnProperty(t)&&void 0!==n&&"function"==typeof n.get&&"function"==typeof n.set){var r=n.get,o=n.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return r.call(this)},set:function(e){a=""+e,o.call(this,e)}}),Object.defineProperty(e,t,{enumerable:n.enumerable}),{getValue:function(){return a},setValue:function(e){a=""+e},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}(e))}function X(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var n=t.getValue(),a="";return e&&(a=K(e)?e.checked?"true":"false":e.value),(e=a)!==n&&(t.setValue(e),!0)}function Z(e){if(void 0===(e=e||("undefined"!=typeof document?document:void 0)))return null;try{return e.activeElement||e.body}catch(t){return e.body}}function J(e,t){var n=t.checked;return r({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:null!=n?n:e._wrapperState.initialChecked})}function ee(e,t){var n=null==t.defaultValue?"":t.defaultValue,a=null!=t.checked?t.checked:t.defaultChecked;n=Y(null!=t.value?t.value:n),e._wrapperState={initialChecked:a,initialValue:n,controlled:"checkbox"===t.type||"radio"===t.type?null!=t.checked:null!=t.value}}function te(e,t){null!=(t=t.checked)&&x(e,"checked",t,!1)}function ne(e,t){te(e,t);var n=Y(t.value),a=t.type;if(null!=n)"number"===a?(0===n&&""===e.value||e.value!=n)&&(e.value=""+n):e.value!==""+n&&(e.value=""+n);else if("submit"===a||"reset"===a)return void e.removeAttribute("value");t.hasOwnProperty("value")?re(e,t.type,n):t.hasOwnProperty("defaultValue")&&re(e,t.type,Y(t.defaultValue)),null==t.checked&&null!=t.defaultChecked&&(e.defaultChecked=!!t.defaultChecked)}function ae(e,t,n){if(t.hasOwnProperty("value")||t.hasOwnProperty("defaultValue")){var a=t.type;if(!("submit"!==a&&"reset"!==a||void 0!==t.value&&null!==t.value))return;t=""+e._wrapperState.initialValue,n||t===e.value||(e.value=t),e.defaultValue=t}""!==(n=e.name)&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,""!==n&&(e.name=n)}function re(e,t,n){"number"===t&&Z(e.ownerDocument)===e||(null==n?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+n&&(e.defaultValue=""+n))}function oe(e,t){return e=r({children:void 0},t),(t=function(e){var t="";return a.Children.forEach(e,(function(e){null!=e&&(t+=e)})),t}(t.children))&&(e.children=t),e}function se(e,t,n,a){if(e=e.options,t){t={};for(var r=0;r<n.length;r++)t["$"+n[r]]=!0;for(n=0;n<e.length;n++)r=t.hasOwnProperty("$"+e[n].value),e[n].selected!==r&&(e[n].selected=r),r&&a&&(e[n].defaultSelected=!0)}else{for(n=""+Y(n),t=null,r=0;r<e.length;r++){if(e[r].value===n)return e[r].selected=!0,void(a&&(e[r].defaultSelected=!0));null!==t||e[r].disabled||(t=e[r])}null!==t&&(t.selected=!0)}}function ie(e,t){if(null!=t.dangerouslySetInnerHTML)throw Error(s(91));return r({},t,{value:void 0,defaultValue:void 0,children:""+e._wrapperState.initialValue})}function le(e,t){var n=t.value;if(null==n){if(n=t.children,t=t.defaultValue,null!=n){if(null!=t)throw Error(s(92));if(Array.isArray(n)){if(!(1>=n.length))throw Error(s(93));n=n[0]}t=n}null==t&&(t=""),n=t}e._wrapperState={initialValue:Y(n)}}function ce(e,t){var n=Y(t.value),a=Y(t.defaultValue);null!=n&&((n=""+n)!==e.value&&(e.value=n),null==t.defaultValue&&e.defaultValue!==n&&(e.defaultValue=n)),null!=a&&(e.defaultValue=""+a)}function ue(e){var t=e.textContent;t===e._wrapperState.initialValue&&""!==t&&null!==t&&(e.value=t)}var de={html:"http://www.w3.org/1999/xhtml",mathml:"http://www.w3.org/1998/Math/MathML",svg:"http://www.w3.org/2000/svg"};function fe(e){switch(e){case"svg":return"http://www.w3.org/2000/svg";case"math":return"http://www.w3.org/1998/Math/MathML";default:return"http://www.w3.org/1999/xhtml"}}function pe(e,t){return null==e||"http://www.w3.org/1999/xhtml"===e?fe(t):"http://www.w3.org/2000/svg"===e&&"foreignObject"===t?"http://www.w3.org/1999/xhtml":e}var me,ge,he=(ge=function(e,t){if(e.namespaceURI!==de.svg||"innerHTML"in e)e.innerHTML=t;else{for((me=me||document.createElement("div")).innerHTML="<svg>"+t.valueOf().toString()+"</svg>",t=me.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;t.firstChild;)e.appendChild(t.firstChild)}},"undefined"!=typeof MSApp&&MSApp.execUnsafeLocalFunction?function(e,t,n,a){MSApp.execUnsafeLocalFunction((function(){return ge(e,t)}))}:ge);function be(e,t){if(t){var n=e.firstChild;if(n&&n===e.lastChild&&3===n.nodeType)return void(n.nodeValue=t)}e.textContent=t}var ye={animationIterationCount:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},ve=["Webkit","ms","Moz","O"];function xe(e,t,n){return null==t||"boolean"==typeof t||""===t?"":n||"number"!=typeof t||0===t||ye.hasOwnProperty(e)&&ye[e]?(""+t).trim():t+"px"}function we(e,t){for(var n in e=e.style,t)if(t.hasOwnProperty(n)){var a=0===n.indexOf("--"),r=xe(n,t[n],a);"float"===n&&(n="cssFloat"),a?e.setProperty(n,r):e[n]=r}}Object.keys(ye).forEach((function(e){ve.forEach((function(t){t=t+e.charAt(0).toUpperCase()+e.substring(1),ye[t]=ye[e]}))}));var Se=r({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function Ee(e,t){if(t){if(Se[e]&&(null!=t.children||null!=t.dangerouslySetInnerHTML))throw Error(s(137,e));if(null!=t.dangerouslySetInnerHTML){if(null!=t.children)throw Error(s(60));if("object"!=typeof t.dangerouslySetInnerHTML||!("__html"in t.dangerouslySetInnerHTML))throw Error(s(61))}if(null!=t.style&&"object"!=typeof t.style)throw Error(s(62))}}function ke(e,t){if(-1===e.indexOf("-"))return"string"==typeof t.is;switch(e){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}function _e(e){return(e=e.target||e.srcElement||window).correspondingUseElement&&(e=e.correspondingUseElement),3===e.nodeType?e.parentNode:e}var Ae=null,Ce=null,qe=null;function Te(e){if(e=nr(e)){if("function"!=typeof Ae)throw Error(s(280));var t=e.stateNode;t&&(t=rr(t),Ae(e.stateNode,e.type,t))}}function Ne(e){Ce?qe?qe.push(e):qe=[e]:Ce=e}function Le(){if(Ce){var e=Ce,t=qe;if(qe=Ce=null,Te(e),t)for(e=0;e<t.length;e++)Te(t[e])}}function Oe(e,t){return e(t)}function Pe(e,t,n,a,r){return e(t,n,a,r)}function Re(){}var Ie=Oe,Me=!1,De=!1;function Fe(){null===Ce&&null===qe||(Re(),Le())}function Be(e,t){var n=e.stateNode;if(null===n)return null;var a=rr(n);if(null===a)return null;n=a[t];e:switch(t){case"onClick":case"onClickCapture":case"onDoubleClick":case"onDoubleClickCapture":case"onMouseDown":case"onMouseDownCapture":case"onMouseMove":case"onMouseMoveCapture":case"onMouseUp":case"onMouseUpCapture":case"onMouseEnter":(a=!a.disabled)||(a=!("button"===(e=e.type)||"input"===e||"select"===e||"textarea"===e)),e=!a;break e;default:e=!1}if(e)return null;if(n&&"function"!=typeof n)throw Error(s(231,t,typeof n));return n}var je=!1;if(d)try{var ze={};Object.defineProperty(ze,"passive",{get:function(){je=!0}}),window.addEventListener("test",ze,ze),window.removeEventListener("test",ze,ze)}catch(ge){je=!1}function $e(e,t,n,a,r,o,s,i,l){var c=Array.prototype.slice.call(arguments,3);try{t.apply(n,c)}catch(u){this.onError(u)}}var Ue=!1,He=null,Ve=!1,Ge=null,We={onError:function(e){Ue=!0,He=e}};function Ye(e,t,n,a,r,o,s,i,l){Ue=!1,He=null,$e.apply(We,arguments)}function Ke(e){var t=e,n=e;if(e.alternate)for(;t.return;)t=t.return;else{e=t;do{!!(1026&(t=e).flags)&&(n=t.return),e=t.return}while(e)}return 3===t.tag?n:null}function Qe(e){if(13===e.tag){var t=e.memoizedState;if(null===t&&(null!==(e=e.alternate)&&(t=e.memoizedState)),null!==t)return t.dehydrated}return null}function Xe(e){if(Ke(e)!==e)throw Error(s(188))}function Ze(e){if(e=function(e){var t=e.alternate;if(!t){if(null===(t=Ke(e)))throw Error(s(188));return t!==e?null:e}for(var n=e,a=t;;){var r=n.return;if(null===r)break;var o=r.alternate;if(null===o){if(null!==(a=r.return)){n=a;continue}break}if(r.child===o.child){for(o=r.child;o;){if(o===n)return Xe(r),e;if(o===a)return Xe(r),t;o=o.sibling}throw Error(s(188))}if(n.return!==a.return)n=r,a=o;else{for(var i=!1,l=r.child;l;){if(l===n){i=!0,n=r,a=o;break}if(l===a){i=!0,a=r,n=o;break}l=l.sibling}if(!i){for(l=o.child;l;){if(l===n){i=!0,n=o,a=r;break}if(l===a){i=!0,a=o,n=r;break}l=l.sibling}if(!i)throw Error(s(189))}}if(n.alternate!==a)throw Error(s(190))}if(3!==n.tag)throw Error(s(188));return n.stateNode.current===n?e:t}(e),!e)return null;for(var t=e;;){if(5===t.tag||6===t.tag)return t;if(t.child)t.child.return=t,t=t.child;else{if(t===e)break;for(;!t.sibling;){if(!t.return||t.return===e)return null;t=t.return}t.sibling.return=t.return,t=t.sibling}}return null}function Je(e,t){for(var n=e.alternate;null!==t;){if(t===e||t===n)return!0;t=t.return}return!1}var et,tt,nt,at,rt=!1,ot=[],st=null,it=null,lt=null,ct=new Map,ut=new Map,dt=[],ft="mousedown mouseup touchcancel touchend touchstart auxclick dblclick pointercancel pointerdown pointerup dragend dragstart drop compositionend compositionstart keydown keypress keyup input textInput copy cut paste click change contextmenu reset submit".split(" ");function pt(e,t,n,a,r){return{blockedOn:e,domEventName:t,eventSystemFlags:16|n,nativeEvent:r,targetContainers:[a]}}function mt(e,t){switch(e){case"focusin":case"focusout":st=null;break;case"dragenter":case"dragleave":it=null;break;case"mouseover":case"mouseout":lt=null;break;case"pointerover":case"pointerout":ct.delete(t.pointerId);break;case"gotpointercapture":case"lostpointercapture":ut.delete(t.pointerId)}}function gt(e,t,n,a,r,o){return null===e||e.nativeEvent!==o?(e=pt(t,n,a,r,o),null!==t&&(null!==(t=nr(t))&&tt(t)),e):(e.eventSystemFlags|=a,t=e.targetContainers,null!==r&&-1===t.indexOf(r)&&t.push(r),e)}function ht(e){var t=tr(e.target);if(null!==t){var n=Ke(t);if(null!==n)if(13===(t=n.tag)){if(null!==(t=Qe(n)))return e.blockedOn=t,void at(e.lanePriority,(function(){o.unstable_runWithPriority(e.priority,(function(){nt(n)}))}))}else if(3===t&&n.stateNode.hydrate)return void(e.blockedOn=3===n.tag?n.stateNode.containerInfo:null)}e.blockedOn=null}function bt(e){if(null!==e.blockedOn)return!1;for(var t=e.targetContainers;0<t.length;){var n=Zt(e.domEventName,e.eventSystemFlags,t[0],e.nativeEvent);if(null!==n)return null!==(t=nr(n))&&tt(t),e.blockedOn=n,!1;t.shift()}return!0}function yt(e,t,n){bt(e)&&n.delete(t)}function vt(){for(rt=!1;0<ot.length;){var e=ot[0];if(null!==e.blockedOn){null!==(e=nr(e.blockedOn))&&et(e);break}for(var t=e.targetContainers;0<t.length;){var n=Zt(e.domEventName,e.eventSystemFlags,t[0],e.nativeEvent);if(null!==n){e.blockedOn=n;break}t.shift()}null===e.blockedOn&&ot.shift()}null!==st&&bt(st)&&(st=null),null!==it&&bt(it)&&(it=null),null!==lt&&bt(lt)&&(lt=null),ct.forEach(yt),ut.forEach(yt)}function xt(e,t){e.blockedOn===t&&(e.blockedOn=null,rt||(rt=!0,o.unstable_scheduleCallback(o.unstable_NormalPriority,vt)))}function wt(e){function t(t){return xt(t,e)}if(0<ot.length){xt(ot[0],e);for(var n=1;n<ot.length;n++){var a=ot[n];a.blockedOn===e&&(a.blockedOn=null)}}for(null!==st&&xt(st,e),null!==it&&xt(it,e),null!==lt&&xt(lt,e),ct.forEach(t),ut.forEach(t),n=0;n<dt.length;n++)(a=dt[n]).blockedOn===e&&(a.blockedOn=null);for(;0<dt.length&&null===(n=dt[0]).blockedOn;)ht(n),null===n.blockedOn&&dt.shift()}function St(e,t){var n={};return n[e.toLowerCase()]=t.toLowerCase(),n["Webkit"+e]="webkit"+t,n["Moz"+e]="moz"+t,n}var Et={animationend:St("Animation","AnimationEnd"),animationiteration:St("Animation","AnimationIteration"),animationstart:St("Animation","AnimationStart"),transitionend:St("Transition","TransitionEnd")},kt={},_t={};function At(e){if(kt[e])return kt[e];if(!Et[e])return e;var t,n=Et[e];for(t in n)if(n.hasOwnProperty(t)&&t in _t)return kt[e]=n[t];return e}d&&(_t=document.createElement("div").style,"AnimationEvent"in window||(delete Et.animationend.animation,delete Et.animationiteration.animation,delete Et.animationstart.animation),"TransitionEvent"in window||delete Et.transitionend.transition);var Ct=At("animationend"),qt=At("animationiteration"),Tt=At("animationstart"),Nt=At("transitionend"),Lt=new Map,Ot=new Map,Pt=["abort","abort",Ct,"animationEnd",qt,"animationIteration",Tt,"animationStart","canplay","canPlay","canplaythrough","canPlayThrough","durationchange","durationChange","emptied","emptied","encrypted","encrypted","ended","ended","error","error","gotpointercapture","gotPointerCapture","load","load","loadeddata","loadedData","loadedmetadata","loadedMetadata","loadstart","loadStart","lostpointercapture","lostPointerCapture","playing","playing","progress","progress","seeking","seeking","stalled","stalled","suspend","suspend","timeupdate","timeUpdate",Nt,"transitionEnd","waiting","waiting"];function Rt(e,t){for(var n=0;n<e.length;n+=2){var a=e[n],r=e[n+1];r="on"+(r[0].toUpperCase()+r.slice(1)),Ot.set(a,t),Lt.set(a,r),c(r,[a])}}(0,o.unstable_now)();var It=8;function Mt(e){if(1&e)return It=15,1;if(2&e)return It=14,2;if(4&e)return It=13,4;var t=24&e;return 0!==t?(It=12,t):32&e?(It=11,32):0!==(t=192&e)?(It=10,t):256&e?(It=9,256):0!==(t=3584&e)?(It=8,t):4096&e?(It=7,4096):0!==(t=4186112&e)?(It=6,t):0!==(t=62914560&e)?(It=5,t):67108864&e?(It=4,67108864):134217728&e?(It=3,134217728):0!==(t=805306368&e)?(It=2,t):1073741824&e?(It=1,1073741824):(It=8,e)}function Dt(e,t){var n=e.pendingLanes;if(0===n)return It=0;var a=0,r=0,o=e.expiredLanes,s=e.suspendedLanes,i=e.pingedLanes;if(0!==o)a=o,r=It=15;else if(0!==(o=134217727&n)){var l=o&~s;0!==l?(a=Mt(l),r=It):0!==(i&=o)&&(a=Mt(i),r=It)}else 0!==(o=n&~s)?(a=Mt(o),r=It):0!==i&&(a=Mt(i),r=It);if(0===a)return 0;if(a=n&((0>(a=31-Ut(a))?0:1<<a)<<1)-1,0!==t&&t!==a&&!(t&s)){if(Mt(t),r<=It)return t;It=r}if(0!==(t=e.entangledLanes))for(e=e.entanglements,t&=a;0<t;)r=1<<(n=31-Ut(t)),a|=e[n],t&=~r;return a}function Ft(e){return 0!==(e=-1073741825&e.pendingLanes)?e:1073741824&e?1073741824:0}function Bt(e,t){switch(e){case 15:return 1;case 14:return 2;case 12:return 0===(e=jt(24&~t))?Bt(10,t):e;case 10:return 0===(e=jt(192&~t))?Bt(8,t):e;case 8:return 0===(e=jt(3584&~t))&&(0===(e=jt(4186112&~t))&&(e=512)),e;case 2:return 0===(t=jt(805306368&~t))&&(t=268435456),t}throw Error(s(358,e))}function jt(e){return e&-e}function zt(e){for(var t=[],n=0;31>n;n++)t.push(e);return t}function $t(e,t,n){e.pendingLanes|=t;var a=t-1;e.suspendedLanes&=a,e.pingedLanes&=a,(e=e.eventTimes)[t=31-Ut(t)]=n}var Ut=Math.clz32?Math.clz32:function(e){return 0===e?32:31-(Ht(e)/Vt|0)|0},Ht=Math.log,Vt=Math.LN2;var Gt=o.unstable_UserBlockingPriority,Wt=o.unstable_runWithPriority,Yt=!0;function Kt(e,t,n,a){Me||Re();var r=Xt,o=Me;Me=!0;try{Pe(r,e,t,n,a)}finally{(Me=o)||Fe()}}function Qt(e,t,n,a){Wt(Gt,Xt.bind(null,e,t,n,a))}function Xt(e,t,n,a){var r;if(Yt)if((r=!(4&t))&&0<ot.length&&-1<ft.indexOf(e))e=pt(null,e,t,n,a),ot.push(e);else{var o=Zt(e,t,n,a);if(null===o)r&&mt(e,a);else{if(r){if(-1<ft.indexOf(e))return e=pt(o,e,t,n,a),void ot.push(e);if(function(e,t,n,a,r){switch(t){case"focusin":return st=gt(st,e,t,n,a,r),!0;case"dragenter":return it=gt(it,e,t,n,a,r),!0;case"mouseover":return lt=gt(lt,e,t,n,a,r),!0;case"pointerover":var o=r.pointerId;return ct.set(o,gt(ct.get(o)||null,e,t,n,a,r)),!0;case"gotpointercapture":return o=r.pointerId,ut.set(o,gt(ut.get(o)||null,e,t,n,a,r)),!0}return!1}(o,e,t,n,a))return;mt(e,a)}Ra(e,t,a,null,n)}}}function Zt(e,t,n,a){var r=_e(a);if(null!==(r=tr(r))){var o=Ke(r);if(null===o)r=null;else{var s=o.tag;if(13===s){if(null!==(r=Qe(o)))return r;r=null}else if(3===s){if(o.stateNode.hydrate)return 3===o.tag?o.stateNode.containerInfo:null;r=null}else o!==r&&(r=null)}}return Ra(e,t,a,r,n),null}var Jt=null,en=null,tn=null;function nn(){if(tn)return tn;var e,t,n=en,a=n.length,r="value"in Jt?Jt.value:Jt.textContent,o=r.length;for(e=0;e<a&&n[e]===r[e];e++);var s=a-e;for(t=1;t<=s&&n[a-t]===r[o-t];t++);return tn=r.slice(e,1<t?1-t:void 0)}function an(e){var t=e.keyCode;return"charCode"in e?0===(e=e.charCode)&&13===t&&(e=13):e=t,10===e&&(e=13),32<=e||13===e?e:0}function rn(){return!0}function on(){return!1}function sn(e){function t(t,n,a,r,o){for(var s in this._reactName=t,this._targetInst=a,this.type=n,this.nativeEvent=r,this.target=o,this.currentTarget=null,e)e.hasOwnProperty(s)&&(t=e[s],this[s]=t?t(r):r[s]);return this.isDefaultPrevented=(null!=r.defaultPrevented?r.defaultPrevented:!1===r.returnValue)?rn:on,this.isPropagationStopped=on,this}return r(t.prototype,{preventDefault:function(){this.defaultPrevented=!0;var e=this.nativeEvent;e&&(e.preventDefault?e.preventDefault():"unknown"!=typeof e.returnValue&&(e.returnValue=!1),this.isDefaultPrevented=rn)},stopPropagation:function(){var e=this.nativeEvent;e&&(e.stopPropagation?e.stopPropagation():"unknown"!=typeof e.cancelBubble&&(e.cancelBubble=!0),this.isPropagationStopped=rn)},persist:function(){},isPersistent:rn}),t}var ln,cn,un,dn={eventPhase:0,bubbles:0,cancelable:0,timeStamp:function(e){return e.timeStamp||Date.now()},defaultPrevented:0,isTrusted:0},fn=sn(dn),pn=r({},dn,{view:0,detail:0}),mn=sn(pn),gn=r({},pn,{screenX:0,screenY:0,clientX:0,clientY:0,pageX:0,pageY:0,ctrlKey:0,shiftKey:0,altKey:0,metaKey:0,getModifierState:Cn,button:0,buttons:0,relatedTarget:function(e){return void 0===e.relatedTarget?e.fromElement===e.srcElement?e.toElement:e.fromElement:e.relatedTarget},movementX:function(e){return"movementX"in e?e.movementX:(e!==un&&(un&&"mousemove"===e.type?(ln=e.screenX-un.screenX,cn=e.screenY-un.screenY):cn=ln=0,un=e),ln)},movementY:function(e){return"movementY"in e?e.movementY:cn}}),hn=sn(gn),bn=sn(r({},gn,{dataTransfer:0})),yn=sn(r({},pn,{relatedTarget:0})),vn=sn(r({},dn,{animationName:0,elapsedTime:0,pseudoElement:0})),xn=r({},dn,{clipboardData:function(e){return"clipboardData"in e?e.clipboardData:window.clipboardData}}),wn=sn(xn),Sn=sn(r({},dn,{data:0})),En={Esc:"Escape",Spacebar:" ",Left:"ArrowLeft",Up:"ArrowUp",Right:"ArrowRight",Down:"ArrowDown",Del:"Delete",Win:"OS",Menu:"ContextMenu",Apps:"ContextMenu",Scroll:"ScrollLock",MozPrintableKey:"Unidentified"},kn={8:"Backspace",9:"Tab",12:"Clear",13:"Enter",16:"Shift",17:"Control",18:"Alt",19:"Pause",20:"CapsLock",27:"Escape",32:" ",33:"PageUp",34:"PageDown",35:"End",36:"Home",37:"ArrowLeft",38:"ArrowUp",39:"ArrowRight",40:"ArrowDown",45:"Insert",46:"Delete",112:"F1",113:"F2",114:"F3",115:"F4",116:"F5",117:"F6",118:"F7",119:"F8",120:"F9",121:"F10",122:"F11",123:"F12",144:"NumLock",145:"ScrollLock",224:"Meta"},_n={Alt:"altKey",Control:"ctrlKey",Meta:"metaKey",Shift:"shiftKey"};function An(e){var t=this.nativeEvent;return t.getModifierState?t.getModifierState(e):!!(e=_n[e])&&!!t[e]}function Cn(){return An}var qn=r({},pn,{key:function(e){if(e.key){var t=En[e.key]||e.key;if("Unidentified"!==t)return t}return"keypress"===e.type?13===(e=an(e))?"Enter":String.fromCharCode(e):"keydown"===e.type||"keyup"===e.type?kn[e.keyCode]||"Unidentified":""},code:0,location:0,ctrlKey:0,shiftKey:0,altKey:0,metaKey:0,repeat:0,locale:0,getModifierState:Cn,charCode:function(e){return"keypress"===e.type?an(e):0},keyCode:function(e){return"keydown"===e.type||"keyup"===e.type?e.keyCode:0},which:function(e){return"keypress"===e.type?an(e):"keydown"===e.type||"keyup"===e.type?e.keyCode:0}}),Tn=sn(qn),Nn=sn(r({},gn,{pointerId:0,width:0,height:0,pressure:0,tangentialPressure:0,tiltX:0,tiltY:0,twist:0,pointerType:0,isPrimary:0})),Ln=sn(r({},pn,{touches:0,targetTouches:0,changedTouches:0,altKey:0,metaKey:0,ctrlKey:0,shiftKey:0,getModifierState:Cn})),On=sn(r({},dn,{propertyName:0,elapsedTime:0,pseudoElement:0})),Pn=r({},gn,{deltaX:function(e){return"deltaX"in e?e.deltaX:"wheelDeltaX"in e?-e.wheelDeltaX:0},deltaY:function(e){return"deltaY"in e?e.deltaY:"wheelDeltaY"in e?-e.wheelDeltaY:"wheelDelta"in e?-e.wheelDelta:0},deltaZ:0,deltaMode:0}),Rn=sn(Pn),In=[9,13,27,32],Mn=d&&"CompositionEvent"in window,Dn=null;d&&"documentMode"in document&&(Dn=document.documentMode);var Fn=d&&"TextEvent"in window&&!Dn,Bn=d&&(!Mn||Dn&&8<Dn&&11>=Dn),jn=String.fromCharCode(32),zn=!1;function $n(e,t){switch(e){case"keyup":return-1!==In.indexOf(t.keyCode);case"keydown":return 229!==t.keyCode;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function Un(e){return"object"==typeof(e=e.detail)&&"data"in e?e.data:null}var Hn=!1;var Vn={color:!0,date:!0,datetime:!0,"datetime-local":!0,email:!0,month:!0,number:!0,password:!0,range:!0,search:!0,tel:!0,text:!0,time:!0,url:!0,week:!0};function Gn(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return"input"===t?!!Vn[e.type]:"textarea"===t}function Wn(e,t,n,a){Ne(a),0<(t=Ma(t,"onChange")).length&&(n=new fn("onChange","change",null,n,a),e.push({event:n,listeners:t}))}var Yn=null,Kn=null;function Qn(e){qa(e,0)}function Xn(e){if(X(ar(e)))return e}function Zn(e,t){if("change"===e)return t}var Jn=!1;if(d){var ea;if(d){var ta="oninput"in document;if(!ta){var na=document.createElement("div");na.setAttribute("oninput","return;"),ta="function"==typeof na.oninput}ea=ta}else ea=!1;Jn=ea&&(!document.documentMode||9<document.documentMode)}function aa(){Yn&&(Yn.detachEvent("onpropertychange",ra),Kn=Yn=null)}function ra(e){if("value"===e.propertyName&&Xn(Kn)){var t=[];if(Wn(t,Kn,e,_e(e)),e=Qn,Me)e(t);else{Me=!0;try{Oe(e,t)}finally{Me=!1,Fe()}}}}function oa(e,t,n){"focusin"===e?(aa(),Kn=n,(Yn=t).attachEvent("onpropertychange",ra)):"focusout"===e&&aa()}function sa(e){if("selectionchange"===e||"keyup"===e||"keydown"===e)return Xn(Kn)}function ia(e,t){if("click"===e)return Xn(t)}function la(e,t){if("input"===e||"change"===e)return Xn(t)}var ca="function"==typeof Object.is?Object.is:function(e,t){return e===t&&(0!==e||1/e==1/t)||e!=e&&t!=t},ua=Object.prototype.hasOwnProperty;function da(e,t){if(ca(e,t))return!0;if("object"!=typeof e||null===e||"object"!=typeof t||null===t)return!1;var n=Object.keys(e),a=Object.keys(t);if(n.length!==a.length)return!1;for(a=0;a<n.length;a++)if(!ua.call(t,n[a])||!ca(e[n[a]],t[n[a]]))return!1;return!0}function fa(e){for(;e&&e.firstChild;)e=e.firstChild;return e}function pa(e,t){var n,a=fa(e);for(e=0;a;){if(3===a.nodeType){if(n=e+a.textContent.length,e<=t&&n>=t)return{node:a,offset:t-e};e=n}e:{for(;a;){if(a.nextSibling){a=a.nextSibling;break e}a=a.parentNode}a=void 0}a=fa(a)}}function ma(e,t){return!(!e||!t)&&(e===t||(!e||3!==e.nodeType)&&(t&&3===t.nodeType?ma(e,t.parentNode):"contains"in e?e.contains(t):!!e.compareDocumentPosition&&!!(16&e.compareDocumentPosition(t))))}function ga(){for(var e=window,t=Z();t instanceof e.HTMLIFrameElement;){try{var n="string"==typeof t.contentWindow.location.href}catch(a){n=!1}if(!n)break;t=Z((e=t.contentWindow).document)}return t}function ha(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&("input"===t&&("text"===e.type||"search"===e.type||"tel"===e.type||"url"===e.type||"password"===e.type)||"textarea"===t||"true"===e.contentEditable)}var ba=d&&"documentMode"in document&&11>=document.documentMode,ya=null,va=null,xa=null,wa=!1;function Sa(e,t,n){var a=n.window===n?n.document:9===n.nodeType?n:n.ownerDocument;wa||null==ya||ya!==Z(a)||("selectionStart"in(a=ya)&&ha(a)?a={start:a.selectionStart,end:a.selectionEnd}:a={anchorNode:(a=(a.ownerDocument&&a.ownerDocument.defaultView||window).getSelection()).anchorNode,anchorOffset:a.anchorOffset,focusNode:a.focusNode,focusOffset:a.focusOffset},xa&&da(xa,a)||(xa=a,0<(a=Ma(va,"onSelect")).length&&(t=new fn("onSelect","select",null,t,n),e.push({event:t,listeners:a}),t.target=ya)))}Rt("cancel cancel click click close close contextmenu contextMenu copy copy cut cut auxclick auxClick dblclick doubleClick dragend dragEnd dragstart dragStart drop drop focusin focus focusout blur input input invalid invalid keydown keyDown keypress keyPress keyup keyUp mousedown mouseDown mouseup mouseUp paste paste pause pause play play pointercancel pointerCancel pointerdown pointerDown pointerup pointerUp ratechange rateChange reset reset seeked seeked submit submit touchcancel touchCancel touchend touchEnd touchstart touchStart volumechange volumeChange".split(" "),0),Rt("drag drag dragenter dragEnter dragexit dragExit dragleave dragLeave dragover dragOver mousemove mouseMove mouseout mouseOut mouseover mouseOver pointermove pointerMove pointerout pointerOut pointerover pointerOver scroll scroll toggle toggle touchmove touchMove wheel wheel".split(" "),1),Rt(Pt,2);for(var Ea="change selectionchange textInput compositionstart compositionend compositionupdate".split(" "),ka=0;ka<Ea.length;ka++)Ot.set(Ea[ka],0);u("onMouseEnter",["mouseout","mouseover"]),u("onMouseLeave",["mouseout","mouseover"]),u("onPointerEnter",["pointerout","pointerover"]),u("onPointerLeave",["pointerout","pointerover"]),c("onChange","change click focusin focusout input keydown keyup selectionchange".split(" ")),c("onSelect","focusout contextmenu dragend focusin keydown keyup mousedown mouseup selectionchange".split(" ")),c("onBeforeInput",["compositionend","keypress","textInput","paste"]),c("onCompositionEnd","compositionend focusout keydown keypress keyup mousedown".split(" ")),c("onCompositionStart","compositionstart focusout keydown keypress keyup mousedown".split(" ")),c("onCompositionUpdate","compositionupdate focusout keydown keypress keyup mousedown".split(" "));var _a="abort canplay canplaythrough durationchange emptied encrypted ended error loadeddata loadedmetadata loadstart pause play playing progress ratechange seeked seeking stalled suspend timeupdate volumechange waiting".split(" "),Aa=new Set("cancel close invalid load scroll toggle".split(" ").concat(_a));function Ca(e,t,n){var a=e.type||"unknown-event";e.currentTarget=n,function(e,t,n,a,r,o,i,l,c){if(Ye.apply(this,arguments),Ue){if(!Ue)throw Error(s(198));var u=He;Ue=!1,He=null,Ve||(Ve=!0,Ge=u)}}(a,t,void 0,e),e.currentTarget=null}function qa(e,t){t=!!(4&t);for(var n=0;n<e.length;n++){var a=e[n],r=a.event;a=a.listeners;e:{var o=void 0;if(t)for(var s=a.length-1;0<=s;s--){var i=a[s],l=i.instance,c=i.currentTarget;if(i=i.listener,l!==o&&r.isPropagationStopped())break e;Ca(r,i,c),o=l}else for(s=0;s<a.length;s++){if(l=(i=a[s]).instance,c=i.currentTarget,i=i.listener,l!==o&&r.isPropagationStopped())break e;Ca(r,i,c),o=l}}}if(Ve)throw e=Ge,Ve=!1,Ge=null,e}function Ta(e,t){var n=or(t),a=e+"__bubble";n.has(a)||(Pa(t,e,2,!1),n.add(a))}var Na="_reactListening"+Math.random().toString(36).slice(2);function La(e){e[Na]||(e[Na]=!0,i.forEach((function(t){Aa.has(t)||Oa(t,!1,e,null),Oa(t,!0,e,null)})))}function Oa(e,t,n,a){var r=4<arguments.length&&void 0!==arguments[4]?arguments[4]:0,o=n;if("selectionchange"===e&&9!==n.nodeType&&(o=n.ownerDocument),null!==a&&!t&&Aa.has(e)){if("scroll"!==e)return;r|=2,o=a}var s=or(o),i=e+"__"+(t?"capture":"bubble");s.has(i)||(t&&(r|=4),Pa(o,e,r,t),s.add(i))}function Pa(e,t,n,a){var r=Ot.get(t);switch(void 0===r?2:r){case 0:r=Kt;break;case 1:r=Qt;break;default:r=Xt}n=r.bind(null,t,n,e),r=void 0,!je||"touchstart"!==t&&"touchmove"!==t&&"wheel"!==t||(r=!0),a?void 0!==r?e.addEventListener(t,n,{capture:!0,passive:r}):e.addEventListener(t,n,!0):void 0!==r?e.addEventListener(t,n,{passive:r}):e.addEventListener(t,n,!1)}function Ra(e,t,n,a,r){var o=a;if(!(1&t||2&t||null===a))e:for(;;){if(null===a)return;var s=a.tag;if(3===s||4===s){var i=a.stateNode.containerInfo;if(i===r||8===i.nodeType&&i.parentNode===r)break;if(4===s)for(s=a.return;null!==s;){var l=s.tag;if((3===l||4===l)&&((l=s.stateNode.containerInfo)===r||8===l.nodeType&&l.parentNode===r))return;s=s.return}for(;null!==i;){if(null===(s=tr(i)))return;if(5===(l=s.tag)||6===l){a=o=s;continue e}i=i.parentNode}}a=a.return}!function(e,t,n){if(De)return e(t,n);De=!0;try{return Ie(e,t,n)}finally{De=!1,Fe()}}((function(){var a=o,r=_e(n),s=[];e:{var i=Lt.get(e);if(void 0!==i){var l=fn,c=e;switch(e){case"keypress":if(0===an(n))break e;case"keydown":case"keyup":l=Tn;break;case"focusin":c="focus",l=yn;break;case"focusout":c="blur",l=yn;break;case"beforeblur":case"afterblur":l=yn;break;case"click":if(2===n.button)break e;case"auxclick":case"dblclick":case"mousedown":case"mousemove":case"mouseup":case"mouseout":case"mouseover":case"contextmenu":l=hn;break;case"drag":case"dragend":case"dragenter":case"dragexit":case"dragleave":case"dragover":case"dragstart":case"drop":l=bn;break;case"touchcancel":case"touchend":case"touchmove":case"touchstart":l=Ln;break;case Ct:case qt:case Tt:l=vn;break;case Nt:l=On;break;case"scroll":l=mn;break;case"wheel":l=Rn;break;case"copy":case"cut":case"paste":l=wn;break;case"gotpointercapture":case"lostpointercapture":case"pointercancel":case"pointerdown":case"pointermove":case"pointerout":case"pointerover":case"pointerup":l=Nn}var u=!!(4&t),d=!u&&"scroll"===e,f=u?null!==i?i+"Capture":null:i;u=[];for(var p,m=a;null!==m;){var g=(p=m).stateNode;if(5===p.tag&&null!==g&&(p=g,null!==f&&(null!=(g=Be(m,f))&&u.push(Ia(m,g,p)))),d)break;m=m.return}0<u.length&&(i=new l(i,c,null,n,r),s.push({event:i,listeners:u}))}}if(!(7&t)){if(l="mouseout"===e||"pointerout"===e,(!(i="mouseover"===e||"pointerover"===e)||16&t||!(c=n.relatedTarget||n.fromElement)||!tr(c)&&!c[Ja])&&(l||i)&&(i=r.window===r?r:(i=r.ownerDocument)?i.defaultView||i.parentWindow:window,l?(l=a,null!==(c=(c=n.relatedTarget||n.toElement)?tr(c):null)&&(c!==(d=Ke(c))||5!==c.tag&&6!==c.tag)&&(c=null)):(l=null,c=a),l!==c)){if(u=hn,g="onMouseLeave",f="onMouseEnter",m="mouse","pointerout"!==e&&"pointerover"!==e||(u=Nn,g="onPointerLeave",f="onPointerEnter",m="pointer"),d=null==l?i:ar(l),p=null==c?i:ar(c),(i=new u(g,m+"leave",l,n,r)).target=d,i.relatedTarget=p,g=null,tr(r)===a&&((u=new u(f,m+"enter",c,n,r)).target=p,u.relatedTarget=d,g=u),d=g,l&&c)e:{for(f=c,m=0,p=u=l;p;p=Da(p))m++;for(p=0,g=f;g;g=Da(g))p++;for(;0<m-p;)u=Da(u),m--;for(;0<p-m;)f=Da(f),p--;for(;m--;){if(u===f||null!==f&&u===f.alternate)break e;u=Da(u),f=Da(f)}u=null}else u=null;null!==l&&Fa(s,i,l,u,!1),null!==c&&null!==d&&Fa(s,d,c,u,!0)}if("select"===(l=(i=a?ar(a):window).nodeName&&i.nodeName.toLowerCase())||"input"===l&&"file"===i.type)var h=Zn;else if(Gn(i))if(Jn)h=la;else{h=sa;var b=oa}else(l=i.nodeName)&&"input"===l.toLowerCase()&&("checkbox"===i.type||"radio"===i.type)&&(h=ia);switch(h&&(h=h(e,a))?Wn(s,h,n,r):(b&&b(e,i,a),"focusout"===e&&(b=i._wrapperState)&&b.controlled&&"number"===i.type&&re(i,"number",i.value)),b=a?ar(a):window,e){case"focusin":(Gn(b)||"true"===b.contentEditable)&&(ya=b,va=a,xa=null);break;case"focusout":xa=va=ya=null;break;case"mousedown":wa=!0;break;case"contextmenu":case"mouseup":case"dragend":wa=!1,Sa(s,n,r);break;case"selectionchange":if(ba)break;case"keydown":case"keyup":Sa(s,n,r)}var y;if(Mn)e:{switch(e){case"compositionstart":var v="onCompositionStart";break e;case"compositionend":v="onCompositionEnd";break e;case"compositionupdate":v="onCompositionUpdate";break e}v=void 0}else Hn?$n(e,n)&&(v="onCompositionEnd"):"keydown"===e&&229===n.keyCode&&(v="onCompositionStart");v&&(Bn&&"ko"!==n.locale&&(Hn||"onCompositionStart"!==v?"onCompositionEnd"===v&&Hn&&(y=nn()):(en="value"in(Jt=r)?Jt.value:Jt.textContent,Hn=!0)),0<(b=Ma(a,v)).length&&(v=new Sn(v,e,null,n,r),s.push({event:v,listeners:b}),y?v.data=y:null!==(y=Un(n))&&(v.data=y))),(y=Fn?function(e,t){switch(e){case"compositionend":return Un(t);case"keypress":return 32!==t.which?null:(zn=!0,jn);case"textInput":return(e=t.data)===jn&&zn?null:e;default:return null}}(e,n):function(e,t){if(Hn)return"compositionend"===e||!Mn&&$n(e,t)?(e=nn(),tn=en=Jt=null,Hn=!1,e):null;switch(e){case"paste":default:return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1<t.char.length)return t.char;if(t.which)return String.fromCharCode(t.which)}return null;case"compositionend":return Bn&&"ko"!==t.locale?null:t.data}}(e,n))&&(0<(a=Ma(a,"onBeforeInput")).length&&(r=new Sn("onBeforeInput","beforeinput",null,n,r),s.push({event:r,listeners:a}),r.data=y))}qa(s,t)}))}function Ia(e,t,n){return{instance:e,listener:t,currentTarget:n}}function Ma(e,t){for(var n=t+"Capture",a=[];null!==e;){var r=e,o=r.stateNode;5===r.tag&&null!==o&&(r=o,null!=(o=Be(e,n))&&a.unshift(Ia(e,o,r)),null!=(o=Be(e,t))&&a.push(Ia(e,o,r))),e=e.return}return a}function Da(e){if(null===e)return null;do{e=e.return}while(e&&5!==e.tag);return e||null}function Fa(e,t,n,a,r){for(var o=t._reactName,s=[];null!==n&&n!==a;){var i=n,l=i.alternate,c=i.stateNode;if(null!==l&&l===a)break;5===i.tag&&null!==c&&(i=c,r?null!=(l=Be(n,o))&&s.unshift(Ia(n,l,i)):r||null!=(l=Be(n,o))&&s.push(Ia(n,l,i))),n=n.return}0!==s.length&&e.push({event:t,listeners:s})}function Ba(){}var ja=null,za=null;function $a(e,t){switch(e){case"button":case"input":case"select":case"textarea":return!!t.autoFocus}return!1}function Ua(e,t){return"textarea"===e||"option"===e||"noscript"===e||"string"==typeof t.children||"number"==typeof t.children||"object"==typeof t.dangerouslySetInnerHTML&&null!==t.dangerouslySetInnerHTML&&null!=t.dangerouslySetInnerHTML.__html}var Ha="function"==typeof setTimeout?setTimeout:void 0,Va="function"==typeof clearTimeout?clearTimeout:void 0;function Ga(e){1===e.nodeType?e.textContent="":9===e.nodeType&&(null!=(e=e.body)&&(e.textContent=""))}function Wa(e){for(;null!=e;e=e.nextSibling){var t=e.nodeType;if(1===t||3===t)break}return e}function Ya(e){e=e.previousSibling;for(var t=0;e;){if(8===e.nodeType){var n=e.data;if("$"===n||"$!"===n||"$?"===n){if(0===t)return e;t--}else"/$"===n&&t++}e=e.previousSibling}return null}var Ka=0;var Qa=Math.random().toString(36).slice(2),Xa="__reactFiber$"+Qa,Za="__reactProps$"+Qa,Ja="__reactContainer$"+Qa,er="__reactEvents$"+Qa;function tr(e){var t=e[Xa];if(t)return t;for(var n=e.parentNode;n;){if(t=n[Ja]||n[Xa]){if(n=t.alternate,null!==t.child||null!==n&&null!==n.child)for(e=Ya(e);null!==e;){if(n=e[Xa])return n;e=Ya(e)}return t}n=(e=n).parentNode}return null}function nr(e){return!(e=e[Xa]||e[Ja])||5!==e.tag&&6!==e.tag&&13!==e.tag&&3!==e.tag?null:e}function ar(e){if(5===e.tag||6===e.tag)return e.stateNode;throw Error(s(33))}function rr(e){return e[Za]||null}function or(e){var t=e[er];return void 0===t&&(t=e[er]=new Set),t}var sr=[],ir=-1;function lr(e){return{current:e}}function cr(e){0>ir||(e.current=sr[ir],sr[ir]=null,ir--)}function ur(e,t){ir++,sr[ir]=e.current,e.current=t}var dr={},fr=lr(dr),pr=lr(!1),mr=dr;function gr(e,t){var n=e.type.contextTypes;if(!n)return dr;var a=e.stateNode;if(a&&a.__reactInternalMemoizedUnmaskedChildContext===t)return a.__reactInternalMemoizedMaskedChildContext;var r,o={};for(r in n)o[r]=t[r];return a&&((e=e.stateNode).__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=o),o}function hr(e){return null!=(e=e.childContextTypes)}function br(){cr(pr),cr(fr)}function yr(e,t,n){if(fr.current!==dr)throw Error(s(168));ur(fr,t),ur(pr,n)}function vr(e,t,n){var a=e.stateNode;if(e=t.childContextTypes,"function"!=typeof a.getChildContext)return n;for(var o in a=a.getChildContext())if(!(o in e))throw Error(s(108,W(t)||"Unknown",o));return r({},n,a)}function xr(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||dr,mr=fr.current,ur(fr,e),ur(pr,pr.current),!0}function wr(e,t,n){var a=e.stateNode;if(!a)throw Error(s(169));n?(e=vr(e,t,mr),a.__reactInternalMemoizedMergedChildContext=e,cr(pr),cr(fr),ur(fr,e)):cr(pr),ur(pr,n)}var Sr=null,Er=null,kr=o.unstable_runWithPriority,_r=o.unstable_scheduleCallback,Ar=o.unstable_cancelCallback,Cr=o.unstable_shouldYield,qr=o.unstable_requestPaint,Tr=o.unstable_now,Nr=o.unstable_getCurrentPriorityLevel,Lr=o.unstable_ImmediatePriority,Or=o.unstable_UserBlockingPriority,Pr=o.unstable_NormalPriority,Rr=o.unstable_LowPriority,Ir=o.unstable_IdlePriority,Mr={},Dr=void 0!==qr?qr:function(){},Fr=null,Br=null,jr=!1,zr=Tr(),$r=1e4>zr?Tr:function(){return Tr()-zr};function Ur(){switch(Nr()){case Lr:return 99;case Or:return 98;case Pr:return 97;case Rr:return 96;case Ir:return 95;default:throw Error(s(332))}}function Hr(e){switch(e){case 99:return Lr;case 98:return Or;case 97:return Pr;case 96:return Rr;case 95:return Ir;default:throw Error(s(332))}}function Vr(e,t){return e=Hr(e),kr(e,t)}function Gr(e,t,n){return e=Hr(e),_r(e,t,n)}function Wr(){if(null!==Br){var e=Br;Br=null,Ar(e)}Yr()}function Yr(){if(!jr&&null!==Fr){jr=!0;var e=0;try{var t=Fr;Vr(99,(function(){for(;e<t.length;e++){var n=t[e];do{n=n(!0)}while(null!==n)}})),Fr=null}catch(n){throw null!==Fr&&(Fr=Fr.slice(e+1)),_r(Lr,Wr),n}finally{jr=!1}}}var Kr=w.ReactCurrentBatchConfig;function Qr(e,t){if(e&&e.defaultProps){for(var n in t=r({},t),e=e.defaultProps)void 0===t[n]&&(t[n]=e[n]);return t}return t}var Xr=lr(null),Zr=null,Jr=null,eo=null;function to(){eo=Jr=Zr=null}function no(e){var t=Xr.current;cr(Xr),e.type._context._currentValue=t}function ao(e,t){for(;null!==e;){var n=e.alternate;if((e.childLanes&t)===t){if(null===n||(n.childLanes&t)===t)break;n.childLanes|=t}else e.childLanes|=t,null!==n&&(n.childLanes|=t);e=e.return}}function ro(e,t){Zr=e,eo=Jr=null,null!==(e=e.dependencies)&&null!==e.firstContext&&(!!(e.lanes&t)&&(Ms=!0),e.firstContext=null)}function oo(e,t){if(eo!==e&&!1!==t&&0!==t)if("number"==typeof t&&1073741823!==t||(eo=e,t=1073741823),t={context:e,observedBits:t,next:null},null===Jr){if(null===Zr)throw Error(s(308));Jr=t,Zr.dependencies={lanes:0,firstContext:t,responders:null}}else Jr=Jr.next=t;return e._currentValue}var so=!1;function io(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null},effects:null}}function lo(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,effects:e.effects})}function co(e,t){return{eventTime:e,lane:t,tag:0,payload:null,callback:null,next:null}}function uo(e,t){if(null!==(e=e.updateQueue)){var n=(e=e.shared).pending;null===n?t.next=t:(t.next=n.next,n.next=t),e.pending=t}}function fo(e,t){var n=e.updateQueue,a=e.alternate;if(null!==a&&n===(a=a.updateQueue)){var r=null,o=null;if(null!==(n=n.firstBaseUpdate)){do{var s={eventTime:n.eventTime,lane:n.lane,tag:n.tag,payload:n.payload,callback:n.callback,next:null};null===o?r=o=s:o=o.next=s,n=n.next}while(null!==n);null===o?r=o=t:o=o.next=t}else r=o=t;return n={baseState:a.baseState,firstBaseUpdate:r,lastBaseUpdate:o,shared:a.shared,effects:a.effects},void(e.updateQueue=n)}null===(e=n.lastBaseUpdate)?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}function po(e,t,n,a){var o=e.updateQueue;so=!1;var s=o.firstBaseUpdate,i=o.lastBaseUpdate,l=o.shared.pending;if(null!==l){o.shared.pending=null;var c=l,u=c.next;c.next=null,null===i?s=u:i.next=u,i=c;var d=e.alternate;if(null!==d){var f=(d=d.updateQueue).lastBaseUpdate;f!==i&&(null===f?d.firstBaseUpdate=u:f.next=u,d.lastBaseUpdate=c)}}if(null!==s){for(f=o.baseState,i=0,d=u=c=null;;){l=s.lane;var p=s.eventTime;if((a&l)===l){null!==d&&(d=d.next={eventTime:p,lane:0,tag:s.tag,payload:s.payload,callback:s.callback,next:null});e:{var m=e,g=s;switch(l=t,p=n,g.tag){case 1:if("function"==typeof(m=g.payload)){f=m.call(p,f,l);break e}f=m;break e;case 3:m.flags=-4097&m.flags|64;case 0:if(null==(l="function"==typeof(m=g.payload)?m.call(p,f,l):m))break e;f=r({},f,l);break e;case 2:so=!0}}null!==s.callback&&(e.flags|=32,null===(l=o.effects)?o.effects=[s]:l.push(s))}else p={eventTime:p,lane:l,tag:s.tag,payload:s.payload,callback:s.callback,next:null},null===d?(u=d=p,c=f):d=d.next=p,i|=l;if(null===(s=s.next)){if(null===(l=o.shared.pending))break;s=l.next,l.next=null,o.lastBaseUpdate=l,o.shared.pending=null}}null===d&&(c=f),o.baseState=c,o.firstBaseUpdate=u,o.lastBaseUpdate=d,zi|=i,e.lanes=i,e.memoizedState=f}}function mo(e,t,n){if(e=t.effects,t.effects=null,null!==e)for(t=0;t<e.length;t++){var a=e[t],r=a.callback;if(null!==r){if(a.callback=null,a=n,"function"!=typeof r)throw Error(s(191,r));r.call(a)}}}var go=(new a.Component).refs;function ho(e,t,n,a){n=null==(n=n(a,t=e.memoizedState))?t:r({},t,n),e.memoizedState=n,0===e.lanes&&(e.updateQueue.baseState=n)}var bo={isMounted:function(e){return!!(e=e._reactInternals)&&Ke(e)===e},enqueueSetState:function(e,t,n){e=e._reactInternals;var a=fl(),r=pl(e),o=co(a,r);o.payload=t,null!=n&&(o.callback=n),uo(e,o),ml(e,r,a)},enqueueReplaceState:function(e,t,n){e=e._reactInternals;var a=fl(),r=pl(e),o=co(a,r);o.tag=1,o.payload=t,null!=n&&(o.callback=n),uo(e,o),ml(e,r,a)},enqueueForceUpdate:function(e,t){e=e._reactInternals;var n=fl(),a=pl(e),r=co(n,a);r.tag=2,null!=t&&(r.callback=t),uo(e,r),ml(e,a,n)}};function yo(e,t,n,a,r,o,s){return"function"==typeof(e=e.stateNode).shouldComponentUpdate?e.shouldComponentUpdate(a,o,s):!t.prototype||!t.prototype.isPureReactComponent||(!da(n,a)||!da(r,o))}function vo(e,t,n){var a=!1,r=dr,o=t.contextType;return"object"==typeof o&&null!==o?o=oo(o):(r=hr(t)?mr:fr.current,o=(a=null!=(a=t.contextTypes))?gr(e,r):dr),t=new t(n,o),e.memoizedState=null!==t.state&&void 0!==t.state?t.state:null,t.updater=bo,e.stateNode=t,t._reactInternals=e,a&&((e=e.stateNode).__reactInternalMemoizedUnmaskedChildContext=r,e.__reactInternalMemoizedMaskedChildContext=o),t}function xo(e,t,n,a){e=t.state,"function"==typeof t.componentWillReceiveProps&&t.componentWillReceiveProps(n,a),"function"==typeof t.UNSAFE_componentWillReceiveProps&&t.UNSAFE_componentWillReceiveProps(n,a),t.state!==e&&bo.enqueueReplaceState(t,t.state,null)}function wo(e,t,n,a){var r=e.stateNode;r.props=n,r.state=e.memoizedState,r.refs=go,io(e);var o=t.contextType;"object"==typeof o&&null!==o?r.context=oo(o):(o=hr(t)?mr:fr.current,r.context=gr(e,o)),po(e,n,r,a),r.state=e.memoizedState,"function"==typeof(o=t.getDerivedStateFromProps)&&(ho(e,t,o,n),r.state=e.memoizedState),"function"==typeof t.getDerivedStateFromProps||"function"==typeof r.getSnapshotBeforeUpdate||"function"!=typeof r.UNSAFE_componentWillMount&&"function"!=typeof r.componentWillMount||(t=r.state,"function"==typeof r.componentWillMount&&r.componentWillMount(),"function"==typeof r.UNSAFE_componentWillMount&&r.UNSAFE_componentWillMount(),t!==r.state&&bo.enqueueReplaceState(r,r.state,null),po(e,n,r,a),r.state=e.memoizedState),"function"==typeof r.componentDidMount&&(e.flags|=4)}var So=Array.isArray;function Eo(e,t,n){if(null!==(e=n.ref)&&"function"!=typeof e&&"object"!=typeof e){if(n._owner){if(n=n._owner){if(1!==n.tag)throw Error(s(309));var a=n.stateNode}if(!a)throw Error(s(147,e));var r=""+e;return null!==t&&null!==t.ref&&"function"==typeof t.ref&&t.ref._stringRef===r?t.ref:(t=function(e){var t=a.refs;t===go&&(t=a.refs={}),null===e?delete t[r]:t[r]=e},t._stringRef=r,t)}if("string"!=typeof e)throw Error(s(284));if(!n._owner)throw Error(s(290,e))}return e}function ko(e,t){if("textarea"!==e.type)throw Error(s(31,"[object Object]"===Object.prototype.toString.call(t)?"object with keys {"+Object.keys(t).join(", ")+"}":t))}function _o(e){function t(t,n){if(e){var a=t.lastEffect;null!==a?(a.nextEffect=n,t.lastEffect=n):t.firstEffect=t.lastEffect=n,n.nextEffect=null,n.flags=8}}function n(n,a){if(!e)return null;for(;null!==a;)t(n,a),a=a.sibling;return null}function a(e,t){for(e=new Map;null!==t;)null!==t.key?e.set(t.key,t):e.set(t.index,t),t=t.sibling;return e}function r(e,t){return(e=Gl(e,t)).index=0,e.sibling=null,e}function o(t,n,a){return t.index=a,e?null!==(a=t.alternate)?(a=a.index)<n?(t.flags=2,n):a:(t.flags=2,n):n}function i(t){return e&&null===t.alternate&&(t.flags=2),t}function l(e,t,n,a){return null===t||6!==t.tag?((t=Ql(n,e.mode,a)).return=e,t):((t=r(t,n)).return=e,t)}function c(e,t,n,a){return null!==t&&t.elementType===n.type?((a=r(t,n.props)).ref=Eo(e,t,n),a.return=e,a):((a=Wl(n.type,n.key,n.props,null,e.mode,a)).ref=Eo(e,t,n),a.return=e,a)}function u(e,t,n,a){return null===t||4!==t.tag||t.stateNode.containerInfo!==n.containerInfo||t.stateNode.implementation!==n.implementation?((t=Xl(n,e.mode,a)).return=e,t):((t=r(t,n.children||[])).return=e,t)}function d(e,t,n,a,o){return null===t||7!==t.tag?((t=Yl(n,e.mode,a,o)).return=e,t):((t=r(t,n)).return=e,t)}function f(e,t,n){if("string"==typeof t||"number"==typeof t)return(t=Ql(""+t,e.mode,n)).return=e,t;if("object"==typeof t&&null!==t){switch(t.$$typeof){case S:return(n=Wl(t.type,t.key,t.props,null,e.mode,n)).ref=Eo(e,null,t),n.return=e,n;case E:return(t=Xl(t,e.mode,n)).return=e,t}if(So(t)||$(t))return(t=Yl(t,e.mode,n,null)).return=e,t;ko(e,t)}return null}function p(e,t,n,a){var r=null!==t?t.key:null;if("string"==typeof n||"number"==typeof n)return null!==r?null:l(e,t,""+n,a);if("object"==typeof n&&null!==n){switch(n.$$typeof){case S:return n.key===r?n.type===k?d(e,t,n.props.children,a,r):c(e,t,n,a):null;case E:return n.key===r?u(e,t,n,a):null}if(So(n)||$(n))return null!==r?null:d(e,t,n,a,null);ko(e,n)}return null}function m(e,t,n,a,r){if("string"==typeof a||"number"==typeof a)return l(t,e=e.get(n)||null,""+a,r);if("object"==typeof a&&null!==a){switch(a.$$typeof){case S:return e=e.get(null===a.key?n:a.key)||null,a.type===k?d(t,e,a.props.children,r,a.key):c(t,e,a,r);case E:return u(t,e=e.get(null===a.key?n:a.key)||null,a,r)}if(So(a)||$(a))return d(t,e=e.get(n)||null,a,r,null);ko(t,a)}return null}function g(r,s,i,l){for(var c=null,u=null,d=s,g=s=0,h=null;null!==d&&g<i.length;g++){d.index>g?(h=d,d=null):h=d.sibling;var b=p(r,d,i[g],l);if(null===b){null===d&&(d=h);break}e&&d&&null===b.alternate&&t(r,d),s=o(b,s,g),null===u?c=b:u.sibling=b,u=b,d=h}if(g===i.length)return n(r,d),c;if(null===d){for(;g<i.length;g++)null!==(d=f(r,i[g],l))&&(s=o(d,s,g),null===u?c=d:u.sibling=d,u=d);return c}for(d=a(r,d);g<i.length;g++)null!==(h=m(d,r,g,i[g],l))&&(e&&null!==h.alternate&&d.delete(null===h.key?g:h.key),s=o(h,s,g),null===u?c=h:u.sibling=h,u=h);return e&&d.forEach((function(e){return t(r,e)})),c}function h(r,i,l,c){var u=$(l);if("function"!=typeof u)throw Error(s(150));if(null==(l=u.call(l)))throw Error(s(151));for(var d=u=null,g=i,h=i=0,b=null,y=l.next();null!==g&&!y.done;h++,y=l.next()){g.index>h?(b=g,g=null):b=g.sibling;var v=p(r,g,y.value,c);if(null===v){null===g&&(g=b);break}e&&g&&null===v.alternate&&t(r,g),i=o(v,i,h),null===d?u=v:d.sibling=v,d=v,g=b}if(y.done)return n(r,g),u;if(null===g){for(;!y.done;h++,y=l.next())null!==(y=f(r,y.value,c))&&(i=o(y,i,h),null===d?u=y:d.sibling=y,d=y);return u}for(g=a(r,g);!y.done;h++,y=l.next())null!==(y=m(g,r,h,y.value,c))&&(e&&null!==y.alternate&&g.delete(null===y.key?h:y.key),i=o(y,i,h),null===d?u=y:d.sibling=y,d=y);return e&&g.forEach((function(e){return t(r,e)})),u}return function(e,a,o,l){var c="object"==typeof o&&null!==o&&o.type===k&&null===o.key;c&&(o=o.props.children);var u="object"==typeof o&&null!==o;if(u)switch(o.$$typeof){case S:e:{for(u=o.key,c=a;null!==c;){if(c.key===u){if(7===c.tag){if(o.type===k){n(e,c.sibling),(a=r(c,o.props.children)).return=e,e=a;break e}}else if(c.elementType===o.type){n(e,c.sibling),(a=r(c,o.props)).ref=Eo(e,c,o),a.return=e,e=a;break e}n(e,c);break}t(e,c),c=c.sibling}o.type===k?((a=Yl(o.props.children,e.mode,l,o.key)).return=e,e=a):((l=Wl(o.type,o.key,o.props,null,e.mode,l)).ref=Eo(e,a,o),l.return=e,e=l)}return i(e);case E:e:{for(c=o.key;null!==a;){if(a.key===c){if(4===a.tag&&a.stateNode.containerInfo===o.containerInfo&&a.stateNode.implementation===o.implementation){n(e,a.sibling),(a=r(a,o.children||[])).return=e,e=a;break e}n(e,a);break}t(e,a),a=a.sibling}(a=Xl(o,e.mode,l)).return=e,e=a}return i(e)}if("string"==typeof o||"number"==typeof o)return o=""+o,null!==a&&6===a.tag?(n(e,a.sibling),(a=r(a,o)).return=e,e=a):(n(e,a),(a=Ql(o,e.mode,l)).return=e,e=a),i(e);if(So(o))return g(e,a,o,l);if($(o))return h(e,a,o,l);if(u&&ko(e,o),void 0===o&&!c)switch(e.tag){case 1:case 22:case 0:case 11:case 15:throw Error(s(152,W(e.type)||"Component"))}return n(e,a)}}var Ao=_o(!0),Co=_o(!1),qo={},To=lr(qo),No=lr(qo),Lo=lr(qo);function Oo(e){if(e===qo)throw Error(s(174));return e}function Po(e,t){switch(ur(Lo,t),ur(No,e),ur(To,qo),e=t.nodeType){case 9:case 11:t=(t=t.documentElement)?t.namespaceURI:pe(null,"");break;default:t=pe(t=(e=8===e?t.parentNode:t).namespaceURI||null,e=e.tagName)}cr(To),ur(To,t)}function Ro(){cr(To),cr(No),cr(Lo)}function Io(e){Oo(Lo.current);var t=Oo(To.current),n=pe(t,e.type);t!==n&&(ur(No,e),ur(To,n))}function Mo(e){No.current===e&&(cr(To),cr(No))}var Do=lr(0);function Fo(e){for(var t=e;null!==t;){if(13===t.tag){var n=t.memoizedState;if(null!==n&&(null===(n=n.dehydrated)||"$?"===n.data||"$!"===n.data))return t}else if(19===t.tag&&void 0!==t.memoizedProps.revealOrder){if(64&t.flags)return t}else if(null!==t.child){t.child.return=t,t=t.child;continue}if(t===e)break;for(;null===t.sibling;){if(null===t.return||t.return===e)return null;t=t.return}t.sibling.return=t.return,t=t.sibling}return null}var Bo=null,jo=null,zo=!1;function $o(e,t){var n=Hl(5,null,null,0);n.elementType="DELETED",n.type="DELETED",n.stateNode=t,n.return=e,n.flags=8,null!==e.lastEffect?(e.lastEffect.nextEffect=n,e.lastEffect=n):e.firstEffect=e.lastEffect=n}function Uo(e,t){switch(e.tag){case 5:var n=e.type;return null!==(t=1!==t.nodeType||n.toLowerCase()!==t.nodeName.toLowerCase()?null:t)&&(e.stateNode=t,!0);case 6:return null!==(t=""===e.pendingProps||3!==t.nodeType?null:t)&&(e.stateNode=t,!0);default:return!1}}function Ho(e){if(zo){var t=jo;if(t){var n=t;if(!Uo(e,t)){if(!(t=Wa(n.nextSibling))||!Uo(e,t))return e.flags=-1025&e.flags|2,zo=!1,void(Bo=e);$o(Bo,n)}Bo=e,jo=Wa(t.firstChild)}else e.flags=-1025&e.flags|2,zo=!1,Bo=e}}function Vo(e){for(e=e.return;null!==e&&5!==e.tag&&3!==e.tag&&13!==e.tag;)e=e.return;Bo=e}function Go(e){if(e!==Bo)return!1;if(!zo)return Vo(e),zo=!0,!1;var t=e.type;if(5!==e.tag||"head"!==t&&"body"!==t&&!Ua(t,e.memoizedProps))for(t=jo;t;)$o(e,t),t=Wa(t.nextSibling);if(Vo(e),13===e.tag){if(!(e=null!==(e=e.memoizedState)?e.dehydrated:null))throw Error(s(317));e:{for(e=e.nextSibling,t=0;e;){if(8===e.nodeType){var n=e.data;if("/$"===n){if(0===t){jo=Wa(e.nextSibling);break e}t--}else"$"!==n&&"$!"!==n&&"$?"!==n||t++}e=e.nextSibling}jo=null}}else jo=Bo?Wa(e.stateNode.nextSibling):null;return!0}function Wo(){jo=Bo=null,zo=!1}var Yo=[];function Ko(){for(var e=0;e<Yo.length;e++)Yo[e]._workInProgressVersionPrimary=null;Yo.length=0}var Qo=w.ReactCurrentDispatcher,Xo=w.ReactCurrentBatchConfig,Zo=0,Jo=null,es=null,ts=null,ns=!1,as=!1;function rs(){throw Error(s(321))}function os(e,t){if(null===t)return!1;for(var n=0;n<t.length&&n<e.length;n++)if(!ca(e[n],t[n]))return!1;return!0}function ss(e,t,n,a,r,o){if(Zo=o,Jo=t,t.memoizedState=null,t.updateQueue=null,t.lanes=0,Qo.current=null===e||null===e.memoizedState?Os:Ps,e=n(a,r),as){o=0;do{if(as=!1,!(25>o))throw Error(s(301));o+=1,ts=es=null,t.updateQueue=null,Qo.current=Rs,e=n(a,r)}while(as)}if(Qo.current=Ls,t=null!==es&&null!==es.next,Zo=0,ts=es=Jo=null,ns=!1,t)throw Error(s(300));return e}function is(){var e={memoizedState:null,baseState:null,baseQueue:null,queue:null,next:null};return null===ts?Jo.memoizedState=ts=e:ts=ts.next=e,ts}function ls(){if(null===es){var e=Jo.alternate;e=null!==e?e.memoizedState:null}else e=es.next;var t=null===ts?Jo.memoizedState:ts.next;if(null!==t)ts=t,es=e;else{if(null===e)throw Error(s(310));e={memoizedState:(es=e).memoizedState,baseState:es.baseState,baseQueue:es.baseQueue,queue:es.queue,next:null},null===ts?Jo.memoizedState=ts=e:ts=ts.next=e}return ts}function cs(e,t){return"function"==typeof t?t(e):t}function us(e){var t=ls(),n=t.queue;if(null===n)throw Error(s(311));n.lastRenderedReducer=e;var a=es,r=a.baseQueue,o=n.pending;if(null!==o){if(null!==r){var i=r.next;r.next=o.next,o.next=i}a.baseQueue=r=o,n.pending=null}if(null!==r){r=r.next,a=a.baseState;var l=i=o=null,c=r;do{var u=c.lane;if((Zo&u)===u)null!==l&&(l=l.next={lane:0,action:c.action,eagerReducer:c.eagerReducer,eagerState:c.eagerState,next:null}),a=c.eagerReducer===e?c.eagerState:e(a,c.action);else{var d={lane:u,action:c.action,eagerReducer:c.eagerReducer,eagerState:c.eagerState,next:null};null===l?(i=l=d,o=a):l=l.next=d,Jo.lanes|=u,zi|=u}c=c.next}while(null!==c&&c!==r);null===l?o=a:l.next=i,ca(a,t.memoizedState)||(Ms=!0),t.memoizedState=a,t.baseState=o,t.baseQueue=l,n.lastRenderedState=a}return[t.memoizedState,n.dispatch]}function ds(e){var t=ls(),n=t.queue;if(null===n)throw Error(s(311));n.lastRenderedReducer=e;var a=n.dispatch,r=n.pending,o=t.memoizedState;if(null!==r){n.pending=null;var i=r=r.next;do{o=e(o,i.action),i=i.next}while(i!==r);ca(o,t.memoizedState)||(Ms=!0),t.memoizedState=o,null===t.baseQueue&&(t.baseState=o),n.lastRenderedState=o}return[o,a]}function fs(e,t,n){var a=t._getVersion;a=a(t._source);var r=t._workInProgressVersionPrimary;if(null!==r?e=r===a:(e=e.mutableReadLanes,(e=(Zo&e)===e)&&(t._workInProgressVersionPrimary=a,Yo.push(t))),e)return n(t._source);throw Yo.push(t),Error(s(350))}function ps(e,t,n,a){var r=Pi;if(null===r)throw Error(s(349));var o=t._getVersion,i=o(t._source),l=Qo.current,c=l.useState((function(){return fs(r,t,n)})),u=c[1],d=c[0];c=ts;var f=e.memoizedState,p=f.refs,m=p.getSnapshot,g=f.source;f=f.subscribe;var h=Jo;return e.memoizedState={refs:p,source:t,subscribe:a},l.useEffect((function(){p.getSnapshot=n,p.setSnapshot=u;var e=o(t._source);if(!ca(i,e)){e=n(t._source),ca(d,e)||(u(e),e=pl(h),r.mutableReadLanes|=e&r.pendingLanes),e=r.mutableReadLanes,r.entangledLanes|=e;for(var a=r.entanglements,s=e;0<s;){var l=31-Ut(s),c=1<<l;a[l]|=e,s&=~c}}}),[n,t,a]),l.useEffect((function(){return a(t._source,(function(){var e=p.getSnapshot,n=p.setSnapshot;try{n(e(t._source));var a=pl(h);r.mutableReadLanes|=a&r.pendingLanes}catch(o){n((function(){throw o}))}}))}),[t,a]),ca(m,n)&&ca(g,t)&&ca(f,a)||((e={pending:null,dispatch:null,lastRenderedReducer:cs,lastRenderedState:d}).dispatch=u=Ns.bind(null,Jo,e),c.queue=e,c.baseQueue=null,d=fs(r,t,n),c.memoizedState=c.baseState=d),d}function ms(e,t,n){return ps(ls(),e,t,n)}function gs(e){var t=is();return"function"==typeof e&&(e=e()),t.memoizedState=t.baseState=e,e=(e=t.queue={pending:null,dispatch:null,lastRenderedReducer:cs,lastRenderedState:e}).dispatch=Ns.bind(null,Jo,e),[t.memoizedState,e]}function hs(e,t,n,a){return e={tag:e,create:t,destroy:n,deps:a,next:null},null===(t=Jo.updateQueue)?(t={lastEffect:null},Jo.updateQueue=t,t.lastEffect=e.next=e):null===(n=t.lastEffect)?t.lastEffect=e.next=e:(a=n.next,n.next=e,e.next=a,t.lastEffect=e),e}function bs(e){return e={current:e},is().memoizedState=e}function ys(){return ls().memoizedState}function vs(e,t,n,a){var r=is();Jo.flags|=e,r.memoizedState=hs(1|t,n,void 0,void 0===a?null:a)}function xs(e,t,n,a){var r=ls();a=void 0===a?null:a;var o=void 0;if(null!==es){var s=es.memoizedState;if(o=s.destroy,null!==a&&os(a,s.deps))return void hs(t,n,o,a)}Jo.flags|=e,r.memoizedState=hs(1|t,n,o,a)}function ws(e,t){return vs(516,4,e,t)}function Ss(e,t){return xs(516,4,e,t)}function Es(e,t){return xs(4,2,e,t)}function ks(e,t){return"function"==typeof t?(e=e(),t(e),function(){t(null)}):null!=t?(e=e(),t.current=e,function(){t.current=null}):void 0}function _s(e,t,n){return n=null!=n?n.concat([e]):null,xs(4,2,ks.bind(null,t,e),n)}function As(){}function Cs(e,t){var n=ls();t=void 0===t?null:t;var a=n.memoizedState;return null!==a&&null!==t&&os(t,a[1])?a[0]:(n.memoizedState=[e,t],e)}function qs(e,t){var n=ls();t=void 0===t?null:t;var a=n.memoizedState;return null!==a&&null!==t&&os(t,a[1])?a[0]:(e=e(),n.memoizedState=[e,t],e)}function Ts(e,t){var n=Ur();Vr(98>n?98:n,(function(){e(!0)})),Vr(97<n?97:n,(function(){var n=Xo.transition;Xo.transition=1;try{e(!1),t()}finally{Xo.transition=n}}))}function Ns(e,t,n){var a=fl(),r=pl(e),o={lane:r,action:n,eagerReducer:null,eagerState:null,next:null},s=t.pending;if(null===s?o.next=o:(o.next=s.next,s.next=o),t.pending=o,s=e.alternate,e===Jo||null!==s&&s===Jo)as=ns=!0;else{if(0===e.lanes&&(null===s||0===s.lanes)&&null!==(s=t.lastRenderedReducer))try{var i=t.lastRenderedState,l=s(i,n);if(o.eagerReducer=s,o.eagerState=l,ca(l,i))return}catch(c){}ml(e,r,a)}}var Ls={readContext:oo,useCallback:rs,useContext:rs,useEffect:rs,useImperativeHandle:rs,useLayoutEffect:rs,useMemo:rs,useReducer:rs,useRef:rs,useState:rs,useDebugValue:rs,useDeferredValue:rs,useTransition:rs,useMutableSource:rs,useOpaqueIdentifier:rs,unstable_isNewReconciler:!1},Os={readContext:oo,useCallback:function(e,t){return is().memoizedState=[e,void 0===t?null:t],e},useContext:oo,useEffect:ws,useImperativeHandle:function(e,t,n){return n=null!=n?n.concat([e]):null,vs(4,2,ks.bind(null,t,e),n)},useLayoutEffect:function(e,t){return vs(4,2,e,t)},useMemo:function(e,t){var n=is();return t=void 0===t?null:t,e=e(),n.memoizedState=[e,t],e},useReducer:function(e,t,n){var a=is();return t=void 0!==n?n(t):t,a.memoizedState=a.baseState=t,e=(e=a.queue={pending:null,dispatch:null,lastRenderedReducer:e,lastRenderedState:t}).dispatch=Ns.bind(null,Jo,e),[a.memoizedState,e]},useRef:bs,useState:gs,useDebugValue:As,useDeferredValue:function(e){var t=gs(e),n=t[0],a=t[1];return ws((function(){var t=Xo.transition;Xo.transition=1;try{a(e)}finally{Xo.transition=t}}),[e]),n},useTransition:function(){var e=gs(!1),t=e[0];return bs(e=Ts.bind(null,e[1])),[e,t]},useMutableSource:function(e,t,n){var a=is();return a.memoizedState={refs:{getSnapshot:t,setSnapshot:null},source:e,subscribe:n},ps(a,e,t,n)},useOpaqueIdentifier:function(){if(zo){var e=!1,t=function(e){return{$$typeof:I,toString:e,valueOf:e}}((function(){throw e||(e=!0,n("r:"+(Ka++).toString(36))),Error(s(355))})),n=gs(t)[1];return!(2&Jo.mode)&&(Jo.flags|=516,hs(5,(function(){n("r:"+(Ka++).toString(36))}),void 0,null)),t}return gs(t="r:"+(Ka++).toString(36)),t},unstable_isNewReconciler:!1},Ps={readContext:oo,useCallback:Cs,useContext:oo,useEffect:Ss,useImperativeHandle:_s,useLayoutEffect:Es,useMemo:qs,useReducer:us,useRef:ys,useState:function(){return us(cs)},useDebugValue:As,useDeferredValue:function(e){var t=us(cs),n=t[0],a=t[1];return Ss((function(){var t=Xo.transition;Xo.transition=1;try{a(e)}finally{Xo.transition=t}}),[e]),n},useTransition:function(){var e=us(cs)[0];return[ys().current,e]},useMutableSource:ms,useOpaqueIdentifier:function(){return us(cs)[0]},unstable_isNewReconciler:!1},Rs={readContext:oo,useCallback:Cs,useContext:oo,useEffect:Ss,useImperativeHandle:_s,useLayoutEffect:Es,useMemo:qs,useReducer:ds,useRef:ys,useState:function(){return ds(cs)},useDebugValue:As,useDeferredValue:function(e){var t=ds(cs),n=t[0],a=t[1];return Ss((function(){var t=Xo.transition;Xo.transition=1;try{a(e)}finally{Xo.transition=t}}),[e]),n},useTransition:function(){var e=ds(cs)[0];return[ys().current,e]},useMutableSource:ms,useOpaqueIdentifier:function(){return ds(cs)[0]},unstable_isNewReconciler:!1},Is=w.ReactCurrentOwner,Ms=!1;function Ds(e,t,n,a){t.child=null===e?Co(t,null,n,a):Ao(t,e.child,n,a)}function Fs(e,t,n,a,r){n=n.render;var o=t.ref;return ro(t,r),a=ss(e,t,n,a,o,r),null===e||Ms?(t.flags|=1,Ds(e,t,a,r),t.child):(t.updateQueue=e.updateQueue,t.flags&=-517,e.lanes&=~r,oi(e,t,r))}function Bs(e,t,n,a,r,o){if(null===e){var s=n.type;return"function"!=typeof s||Vl(s)||void 0!==s.defaultProps||null!==n.compare||void 0!==n.defaultProps?((e=Wl(n.type,null,a,t,t.mode,o)).ref=t.ref,e.return=t,t.child=e):(t.tag=15,t.type=s,js(e,t,s,a,r,o))}return s=e.child,r&o||(r=s.memoizedProps,!(n=null!==(n=n.compare)?n:da)(r,a)||e.ref!==t.ref)?(t.flags|=1,(e=Gl(s,a)).ref=t.ref,e.return=t,t.child=e):oi(e,t,o)}function js(e,t,n,a,r,o){if(null!==e&&da(e.memoizedProps,a)&&e.ref===t.ref){if(Ms=!1,!(o&r))return t.lanes=e.lanes,oi(e,t,o);16384&e.flags&&(Ms=!0)}return Us(e,t,n,a,o)}function zs(e,t,n){var a=t.pendingProps,r=a.children,o=null!==e?e.memoizedState:null;if("hidden"===a.mode||"unstable-defer-without-hiding"===a.mode)if(4&t.mode){if(!(1073741824&n))return e=null!==o?o.baseLanes|n:n,t.lanes=t.childLanes=1073741824,t.memoizedState={baseLanes:e},Sl(t,e),null;t.memoizedState={baseLanes:0},Sl(t,null!==o?o.baseLanes:n)}else t.memoizedState={baseLanes:0},Sl(t,n);else null!==o?(a=o.baseLanes|n,t.memoizedState=null):a=n,Sl(t,a);return Ds(e,t,r,n),t.child}function $s(e,t){var n=t.ref;(null===e&&null!==n||null!==e&&e.ref!==n)&&(t.flags|=128)}function Us(e,t,n,a,r){var o=hr(n)?mr:fr.current;return o=gr(t,o),ro(t,r),n=ss(e,t,n,a,o,r),null===e||Ms?(t.flags|=1,Ds(e,t,n,r),t.child):(t.updateQueue=e.updateQueue,t.flags&=-517,e.lanes&=~r,oi(e,t,r))}function Hs(e,t,n,a,r){if(hr(n)){var o=!0;xr(t)}else o=!1;if(ro(t,r),null===t.stateNode)null!==e&&(e.alternate=null,t.alternate=null,t.flags|=2),vo(t,n,a),wo(t,n,a,r),a=!0;else if(null===e){var s=t.stateNode,i=t.memoizedProps;s.props=i;var l=s.context,c=n.contextType;"object"==typeof c&&null!==c?c=oo(c):c=gr(t,c=hr(n)?mr:fr.current);var u=n.getDerivedStateFromProps,d="function"==typeof u||"function"==typeof s.getSnapshotBeforeUpdate;d||"function"!=typeof s.UNSAFE_componentWillReceiveProps&&"function"!=typeof s.componentWillReceiveProps||(i!==a||l!==c)&&xo(t,s,a,c),so=!1;var f=t.memoizedState;s.state=f,po(t,a,s,r),l=t.memoizedState,i!==a||f!==l||pr.current||so?("function"==typeof u&&(ho(t,n,u,a),l=t.memoizedState),(i=so||yo(t,n,i,a,f,l,c))?(d||"function"!=typeof s.UNSAFE_componentWillMount&&"function"!=typeof s.componentWillMount||("function"==typeof s.componentWillMount&&s.componentWillMount(),"function"==typeof s.UNSAFE_componentWillMount&&s.UNSAFE_componentWillMount()),"function"==typeof s.componentDidMount&&(t.flags|=4)):("function"==typeof s.componentDidMount&&(t.flags|=4),t.memoizedProps=a,t.memoizedState=l),s.props=a,s.state=l,s.context=c,a=i):("function"==typeof s.componentDidMount&&(t.flags|=4),a=!1)}else{s=t.stateNode,lo(e,t),i=t.memoizedProps,c=t.type===t.elementType?i:Qr(t.type,i),s.props=c,d=t.pendingProps,f=s.context,"object"==typeof(l=n.contextType)&&null!==l?l=oo(l):l=gr(t,l=hr(n)?mr:fr.current);var p=n.getDerivedStateFromProps;(u="function"==typeof p||"function"==typeof s.getSnapshotBeforeUpdate)||"function"!=typeof s.UNSAFE_componentWillReceiveProps&&"function"!=typeof s.componentWillReceiveProps||(i!==d||f!==l)&&xo(t,s,a,l),so=!1,f=t.memoizedState,s.state=f,po(t,a,s,r);var m=t.memoizedState;i!==d||f!==m||pr.current||so?("function"==typeof p&&(ho(t,n,p,a),m=t.memoizedState),(c=so||yo(t,n,c,a,f,m,l))?(u||"function"!=typeof s.UNSAFE_componentWillUpdate&&"function"!=typeof s.componentWillUpdate||("function"==typeof s.componentWillUpdate&&s.componentWillUpdate(a,m,l),"function"==typeof s.UNSAFE_componentWillUpdate&&s.UNSAFE_componentWillUpdate(a,m,l)),"function"==typeof s.componentDidUpdate&&(t.flags|=4),"function"==typeof s.getSnapshotBeforeUpdate&&(t.flags|=256)):("function"!=typeof s.componentDidUpdate||i===e.memoizedProps&&f===e.memoizedState||(t.flags|=4),"function"!=typeof s.getSnapshotBeforeUpdate||i===e.memoizedProps&&f===e.memoizedState||(t.flags|=256),t.memoizedProps=a,t.memoizedState=m),s.props=a,s.state=m,s.context=l,a=c):("function"!=typeof s.componentDidUpdate||i===e.memoizedProps&&f===e.memoizedState||(t.flags|=4),"function"!=typeof s.getSnapshotBeforeUpdate||i===e.memoizedProps&&f===e.memoizedState||(t.flags|=256),a=!1)}return Vs(e,t,n,a,o,r)}function Vs(e,t,n,a,r,o){$s(e,t);var s=!!(64&t.flags);if(!a&&!s)return r&&wr(t,n,!1),oi(e,t,o);a=t.stateNode,Is.current=t;var i=s&&"function"!=typeof n.getDerivedStateFromError?null:a.render();return t.flags|=1,null!==e&&s?(t.child=Ao(t,e.child,null,o),t.child=Ao(t,null,i,o)):Ds(e,t,i,o),t.memoizedState=a.state,r&&wr(t,n,!0),t.child}function Gs(e){var t=e.stateNode;t.pendingContext?yr(0,t.pendingContext,t.pendingContext!==t.context):t.context&&yr(0,t.context,!1),Po(e,t.containerInfo)}var Ws,Ys,Ks,Qs,Xs={dehydrated:null,retryLane:0};function Zs(e,t,n){var a,r=t.pendingProps,o=Do.current,s=!1;return(a=!!(64&t.flags))||(a=(null===e||null!==e.memoizedState)&&!!(2&o)),a?(s=!0,t.flags&=-65):null!==e&&null===e.memoizedState||void 0===r.fallback||!0===r.unstable_avoidThisFallback||(o|=1),ur(Do,1&o),null===e?(void 0!==r.fallback&&Ho(t),e=r.children,o=r.fallback,s?(e=Js(t,e,o,n),t.child.memoizedState={baseLanes:n},t.memoizedState=Xs,e):"number"==typeof r.unstable_expectedLoadTime?(e=Js(t,e,o,n),t.child.memoizedState={baseLanes:n},t.memoizedState=Xs,t.lanes=33554432,e):((n=Kl({mode:"visible",children:e},t.mode,n,null)).return=t,t.child=n)):(e.memoizedState,s?(r=ti(e,t,r.children,r.fallback,n),s=t.child,o=e.child.memoizedState,s.memoizedState=null===o?{baseLanes:n}:{baseLanes:o.baseLanes|n},s.childLanes=e.childLanes&~n,t.memoizedState=Xs,r):(n=ei(e,t,r.children,n),t.memoizedState=null,n))}function Js(e,t,n,a){var r=e.mode,o=e.child;return t={mode:"hidden",children:t},2&r||null===o?o=Kl(t,r,0,null):(o.childLanes=0,o.pendingProps=t),n=Yl(n,r,a,null),o.return=e,n.return=e,o.sibling=n,e.child=o,n}function ei(e,t,n,a){var r=e.child;return e=r.sibling,n=Gl(r,{mode:"visible",children:n}),!(2&t.mode)&&(n.lanes=a),n.return=t,n.sibling=null,null!==e&&(e.nextEffect=null,e.flags=8,t.firstEffect=t.lastEffect=e),t.child=n}function ti(e,t,n,a,r){var o=t.mode,s=e.child;e=s.sibling;var i={mode:"hidden",children:n};return 2&o||t.child===s?n=Gl(s,i):((n=t.child).childLanes=0,n.pendingProps=i,null!==(s=n.lastEffect)?(t.firstEffect=n.firstEffect,t.lastEffect=s,s.nextEffect=null):t.firstEffect=t.lastEffect=null),null!==e?a=Gl(e,a):(a=Yl(a,o,r,null)).flags|=2,a.return=t,n.return=t,n.sibling=a,t.child=n,a}function ni(e,t){e.lanes|=t;var n=e.alternate;null!==n&&(n.lanes|=t),ao(e.return,t)}function ai(e,t,n,a,r,o){var s=e.memoizedState;null===s?e.memoizedState={isBackwards:t,rendering:null,renderingStartTime:0,last:a,tail:n,tailMode:r,lastEffect:o}:(s.isBackwards=t,s.rendering=null,s.renderingStartTime=0,s.last=a,s.tail=n,s.tailMode=r,s.lastEffect=o)}function ri(e,t,n){var a=t.pendingProps,r=a.revealOrder,o=a.tail;if(Ds(e,t,a.children,n),2&(a=Do.current))a=1&a|2,t.flags|=64;else{if(null!==e&&64&e.flags)e:for(e=t.child;null!==e;){if(13===e.tag)null!==e.memoizedState&&ni(e,n);else if(19===e.tag)ni(e,n);else if(null!==e.child){e.child.return=e,e=e.child;continue}if(e===t)break e;for(;null===e.sibling;){if(null===e.return||e.return===t)break e;e=e.return}e.sibling.return=e.return,e=e.sibling}a&=1}if(ur(Do,a),2&t.mode)switch(r){case"forwards":for(n=t.child,r=null;null!==n;)null!==(e=n.alternate)&&null===Fo(e)&&(r=n),n=n.sibling;null===(n=r)?(r=t.child,t.child=null):(r=n.sibling,n.sibling=null),ai(t,!1,r,n,o,t.lastEffect);break;case"backwards":for(n=null,r=t.child,t.child=null;null!==r;){if(null!==(e=r.alternate)&&null===Fo(e)){t.child=r;break}e=r.sibling,r.sibling=n,n=r,r=e}ai(t,!0,n,null,o,t.lastEffect);break;case"together":ai(t,!1,null,null,void 0,t.lastEffect);break;default:t.memoizedState=null}else t.memoizedState=null;return t.child}function oi(e,t,n){if(null!==e&&(t.dependencies=e.dependencies),zi|=t.lanes,n&t.childLanes){if(null!==e&&t.child!==e.child)throw Error(s(153));if(null!==t.child){for(n=Gl(e=t.child,e.pendingProps),t.child=n,n.return=t;null!==e.sibling;)e=e.sibling,(n=n.sibling=Gl(e,e.pendingProps)).return=t;n.sibling=null}return t.child}return null}function si(e,t){if(!zo)switch(e.tailMode){case"hidden":t=e.tail;for(var n=null;null!==t;)null!==t.alternate&&(n=t),t=t.sibling;null===n?e.tail=null:n.sibling=null;break;case"collapsed":n=e.tail;for(var a=null;null!==n;)null!==n.alternate&&(a=n),n=n.sibling;null===a?t||null===e.tail?e.tail=null:e.tail.sibling=null:a.sibling=null}}function ii(e,t,n){var a=t.pendingProps;switch(t.tag){case 2:case 16:case 15:case 0:case 11:case 7:case 8:case 12:case 9:case 14:return null;case 1:case 17:return hr(t.type)&&br(),null;case 3:return Ro(),cr(pr),cr(fr),Ko(),(a=t.stateNode).pendingContext&&(a.context=a.pendingContext,a.pendingContext=null),null!==e&&null!==e.child||(Go(t)?t.flags|=4:a.hydrate||(t.flags|=256)),Ys(t),null;case 5:Mo(t);var o=Oo(Lo.current);if(n=t.type,null!==e&&null!=t.stateNode)Ks(e,t,n,a,o),e.ref!==t.ref&&(t.flags|=128);else{if(!a){if(null===t.stateNode)throw Error(s(166));return null}if(e=Oo(To.current),Go(t)){a=t.stateNode,n=t.type;var i=t.memoizedProps;switch(a[Xa]=t,a[Za]=i,n){case"dialog":Ta("cancel",a),Ta("close",a);break;case"iframe":case"object":case"embed":Ta("load",a);break;case"video":case"audio":for(e=0;e<_a.length;e++)Ta(_a[e],a);break;case"source":Ta("error",a);break;case"img":case"image":case"link":Ta("error",a),Ta("load",a);break;case"details":Ta("toggle",a);break;case"input":ee(a,i),Ta("invalid",a);break;case"select":a._wrapperState={wasMultiple:!!i.multiple},Ta("invalid",a);break;case"textarea":le(a,i),Ta("invalid",a)}for(var c in Ee(n,i),e=null,i)i.hasOwnProperty(c)&&(o=i[c],"children"===c?"string"==typeof o?a.textContent!==o&&(e=["children",o]):"number"==typeof o&&a.textContent!==""+o&&(e=["children",""+o]):l.hasOwnProperty(c)&&null!=o&&"onScroll"===c&&Ta("scroll",a));switch(n){case"input":Q(a),ae(a,i,!0);break;case"textarea":Q(a),ue(a);break;case"select":case"option":break;default:"function"==typeof i.onClick&&(a.onclick=Ba)}a=e,t.updateQueue=a,null!==a&&(t.flags|=4)}else{switch(c=9===o.nodeType?o:o.ownerDocument,e===de.html&&(e=fe(n)),e===de.html?"script"===n?((e=c.createElement("div")).innerHTML="<script><\/script>",e=e.removeChild(e.firstChild)):"string"==typeof a.is?e=c.createElement(n,{is:a.is}):(e=c.createElement(n),"select"===n&&(c=e,a.multiple?c.multiple=!0:a.size&&(c.size=a.size))):e=c.createElementNS(e,n),e[Xa]=t,e[Za]=a,Ws(e,t,!1,!1),t.stateNode=e,c=ke(n,a),n){case"dialog":Ta("cancel",e),Ta("close",e),o=a;break;case"iframe":case"object":case"embed":Ta("load",e),o=a;break;case"video":case"audio":for(o=0;o<_a.length;o++)Ta(_a[o],e);o=a;break;case"source":Ta("error",e),o=a;break;case"img":case"image":case"link":Ta("error",e),Ta("load",e),o=a;break;case"details":Ta("toggle",e),o=a;break;case"input":ee(e,a),o=J(e,a),Ta("invalid",e);break;case"option":o=oe(e,a);break;case"select":e._wrapperState={wasMultiple:!!a.multiple},o=r({},a,{value:void 0}),Ta("invalid",e);break;case"textarea":le(e,a),o=ie(e,a),Ta("invalid",e);break;default:o=a}Ee(n,o);var u=o;for(i in u)if(u.hasOwnProperty(i)){var d=u[i];"style"===i?we(e,d):"dangerouslySetInnerHTML"===i?null!=(d=d?d.__html:void 0)&&he(e,d):"children"===i?"string"==typeof d?("textarea"!==n||""!==d)&&be(e,d):"number"==typeof d&&be(e,""+d):"suppressContentEditableWarning"!==i&&"suppressHydrationWarning"!==i&&"autoFocus"!==i&&(l.hasOwnProperty(i)?null!=d&&"onScroll"===i&&Ta("scroll",e):null!=d&&x(e,i,d,c))}switch(n){case"input":Q(e),ae(e,a,!1);break;case"textarea":Q(e),ue(e);break;case"option":null!=a.value&&e.setAttribute("value",""+Y(a.value));break;case"select":e.multiple=!!a.multiple,null!=(i=a.value)?se(e,!!a.multiple,i,!1):null!=a.defaultValue&&se(e,!!a.multiple,a.defaultValue,!0);break;default:"function"==typeof o.onClick&&(e.onclick=Ba)}$a(n,a)&&(t.flags|=4)}null!==t.ref&&(t.flags|=128)}return null;case 6:if(e&&null!=t.stateNode)Qs(e,t,e.memoizedProps,a);else{if("string"!=typeof a&&null===t.stateNode)throw Error(s(166));n=Oo(Lo.current),Oo(To.current),Go(t)?(a=t.stateNode,n=t.memoizedProps,a[Xa]=t,a.nodeValue!==n&&(t.flags|=4)):((a=(9===n.nodeType?n:n.ownerDocument).createTextNode(a))[Xa]=t,t.stateNode=a)}return null;case 13:return cr(Do),a=t.memoizedState,64&t.flags?(t.lanes=n,t):(a=null!==a,n=!1,null===e?void 0!==t.memoizedProps.fallback&&Go(t):n=null!==e.memoizedState,a&&!n&&2&t.mode&&(null===e&&!0!==t.memoizedProps.unstable_avoidThisFallback||1&Do.current?0===Fi&&(Fi=3):(0!==Fi&&3!==Fi||(Fi=4),null===Pi||!(134217727&zi)&&!(134217727&$i)||yl(Pi,Ii))),(a||n)&&(t.flags|=4),null);case 4:return Ro(),Ys(t),null===e&&La(t.stateNode.containerInfo),null;case 10:return no(t),null;case 19:if(cr(Do),null===(a=t.memoizedState))return null;if(i=!!(64&t.flags),null===(c=a.rendering))if(i)si(a,!1);else{if(0!==Fi||null!==e&&64&e.flags)for(e=t.child;null!==e;){if(null!==(c=Fo(e))){for(t.flags|=64,si(a,!1),null!==(i=c.updateQueue)&&(t.updateQueue=i,t.flags|=4),null===a.lastEffect&&(t.firstEffect=null),t.lastEffect=a.lastEffect,a=n,n=t.child;null!==n;)e=a,(i=n).flags&=2,i.nextEffect=null,i.firstEffect=null,i.lastEffect=null,null===(c=i.alternate)?(i.childLanes=0,i.lanes=e,i.child=null,i.memoizedProps=null,i.memoizedState=null,i.updateQueue=null,i.dependencies=null,i.stateNode=null):(i.childLanes=c.childLanes,i.lanes=c.lanes,i.child=c.child,i.memoizedProps=c.memoizedProps,i.memoizedState=c.memoizedState,i.updateQueue=c.updateQueue,i.type=c.type,e=c.dependencies,i.dependencies=null===e?null:{lanes:e.lanes,firstContext:e.firstContext}),n=n.sibling;return ur(Do,1&Do.current|2),t.child}e=e.sibling}null!==a.tail&&$r()>Gi&&(t.flags|=64,i=!0,si(a,!1),t.lanes=33554432)}else{if(!i)if(null!==(e=Fo(c))){if(t.flags|=64,i=!0,null!==(n=e.updateQueue)&&(t.updateQueue=n,t.flags|=4),si(a,!0),null===a.tail&&"hidden"===a.tailMode&&!c.alternate&&!zo)return null!==(t=t.lastEffect=a.lastEffect)&&(t.nextEffect=null),null}else 2*$r()-a.renderingStartTime>Gi&&1073741824!==n&&(t.flags|=64,i=!0,si(a,!1),t.lanes=33554432);a.isBackwards?(c.sibling=t.child,t.child=c):(null!==(n=a.last)?n.sibling=c:t.child=c,a.last=c)}return null!==a.tail?(n=a.tail,a.rendering=n,a.tail=n.sibling,a.lastEffect=t.lastEffect,a.renderingStartTime=$r(),n.sibling=null,t=Do.current,ur(Do,i?1&t|2:1&t),n):null;case 23:case 24:return El(),null!==e&&null!==e.memoizedState!=(null!==t.memoizedState)&&"unstable-defer-without-hiding"!==a.mode&&(t.flags|=4),null}throw Error(s(156,t.tag))}function li(e){switch(e.tag){case 1:hr(e.type)&&br();var t=e.flags;return 4096&t?(e.flags=-4097&t|64,e):null;case 3:if(Ro(),cr(pr),cr(fr),Ko(),64&(t=e.flags))throw Error(s(285));return e.flags=-4097&t|64,e;case 5:return Mo(e),null;case 13:return cr(Do),4096&(t=e.flags)?(e.flags=-4097&t|64,e):null;case 19:return cr(Do),null;case 4:return Ro(),null;case 10:return no(e),null;case 23:case 24:return El(),null;default:return null}}function ci(e,t){try{var n="",a=t;do{n+=G(a),a=a.return}while(a);var r=n}catch(o){r="\nError generating stack: "+o.message+"\n"+o.stack}return{value:e,source:t,stack:r}}function ui(e,t){try{console.error(t.value)}catch(n){setTimeout((function(){throw n}))}}Ws=function(e,t){for(var n=t.child;null!==n;){if(5===n.tag||6===n.tag)e.appendChild(n.stateNode);else if(4!==n.tag&&null!==n.child){n.child.return=n,n=n.child;continue}if(n===t)break;for(;null===n.sibling;){if(null===n.return||n.return===t)return;n=n.return}n.sibling.return=n.return,n=n.sibling}},Ys=function(){},Ks=function(e,t,n,a){var o=e.memoizedProps;if(o!==a){e=t.stateNode,Oo(To.current);var s,i=null;switch(n){case"input":o=J(e,o),a=J(e,a),i=[];break;case"option":o=oe(e,o),a=oe(e,a),i=[];break;case"select":o=r({},o,{value:void 0}),a=r({},a,{value:void 0}),i=[];break;case"textarea":o=ie(e,o),a=ie(e,a),i=[];break;default:"function"!=typeof o.onClick&&"function"==typeof a.onClick&&(e.onclick=Ba)}for(d in Ee(n,a),n=null,o)if(!a.hasOwnProperty(d)&&o.hasOwnProperty(d)&&null!=o[d])if("style"===d){var c=o[d];for(s in c)c.hasOwnProperty(s)&&(n||(n={}),n[s]="")}else"dangerouslySetInnerHTML"!==d&&"children"!==d&&"suppressContentEditableWarning"!==d&&"suppressHydrationWarning"!==d&&"autoFocus"!==d&&(l.hasOwnProperty(d)?i||(i=[]):(i=i||[]).push(d,null));for(d in a){var u=a[d];if(c=null!=o?o[d]:void 0,a.hasOwnProperty(d)&&u!==c&&(null!=u||null!=c))if("style"===d)if(c){for(s in c)!c.hasOwnProperty(s)||u&&u.hasOwnProperty(s)||(n||(n={}),n[s]="");for(s in u)u.hasOwnProperty(s)&&c[s]!==u[s]&&(n||(n={}),n[s]=u[s])}else n||(i||(i=[]),i.push(d,n)),n=u;else"dangerouslySetInnerHTML"===d?(u=u?u.__html:void 0,c=c?c.__html:void 0,null!=u&&c!==u&&(i=i||[]).push(d,u)):"children"===d?"string"!=typeof u&&"number"!=typeof u||(i=i||[]).push(d,""+u):"suppressContentEditableWarning"!==d&&"suppressHydrationWarning"!==d&&(l.hasOwnProperty(d)?(null!=u&&"onScroll"===d&&Ta("scroll",e),i||c===u||(i=[])):"object"==typeof u&&null!==u&&u.$$typeof===I?u.toString():(i=i||[]).push(d,u))}n&&(i=i||[]).push("style",n);var d=i;(t.updateQueue=d)&&(t.flags|=4)}},Qs=function(e,t,n,a){n!==a&&(t.flags|=4)};var di="function"==typeof WeakMap?WeakMap:Map;function fi(e,t,n){(n=co(-1,n)).tag=3,n.payload={element:null};var a=t.value;return n.callback=function(){Qi||(Qi=!0,Xi=a),ui(0,t)},n}function pi(e,t,n){(n=co(-1,n)).tag=3;var a=e.type.getDerivedStateFromError;if("function"==typeof a){var r=t.value;n.payload=function(){return ui(0,t),a(r)}}var o=e.stateNode;return null!==o&&"function"==typeof o.componentDidCatch&&(n.callback=function(){"function"!=typeof a&&(null===Zi?Zi=new Set([this]):Zi.add(this),ui(0,t));var e=t.stack;this.componentDidCatch(t.value,{componentStack:null!==e?e:""})}),n}var mi="function"==typeof WeakSet?WeakSet:Set;function gi(e){var t=e.ref;if(null!==t)if("function"==typeof t)try{t(null)}catch(n){jl(e,n)}else t.current=null}function hi(e,t){switch(t.tag){case 0:case 11:case 15:case 22:case 5:case 6:case 4:case 17:return;case 1:if(256&t.flags&&null!==e){var n=e.memoizedProps,a=e.memoizedState;t=(e=t.stateNode).getSnapshotBeforeUpdate(t.elementType===t.type?n:Qr(t.type,n),a),e.__reactInternalSnapshotBeforeUpdate=t}return;case 3:return void(256&t.flags&&Ga(t.stateNode.containerInfo))}throw Error(s(163))}function bi(e,t,n){switch(n.tag){case 0:case 11:case 15:case 22:if(null!==(t=null!==(t=n.updateQueue)?t.lastEffect:null)){e=t=t.next;do{if(!(3&~e.tag)){var a=e.create;e.destroy=a()}e=e.next}while(e!==t)}if(null!==(t=null!==(t=n.updateQueue)?t.lastEffect:null)){e=t=t.next;do{var r=e;a=r.next,4&(r=r.tag)&&1&r&&(Dl(n,e),Ml(n,e)),e=a}while(e!==t)}return;case 1:return e=n.stateNode,4&n.flags&&(null===t?e.componentDidMount():(a=n.elementType===n.type?t.memoizedProps:Qr(n.type,t.memoizedProps),e.componentDidUpdate(a,t.memoizedState,e.__reactInternalSnapshotBeforeUpdate))),void(null!==(t=n.updateQueue)&&mo(n,t,e));case 3:if(null!==(t=n.updateQueue)){if(e=null,null!==n.child)switch(n.child.tag){case 5:case 1:e=n.child.stateNode}mo(n,t,e)}return;case 5:return e=n.stateNode,void(null===t&&4&n.flags&&$a(n.type,n.memoizedProps)&&e.focus());case 6:case 4:case 12:case 19:case 17:case 20:case 21:case 23:case 24:return;case 13:return void(null===n.memoizedState&&(n=n.alternate,null!==n&&(n=n.memoizedState,null!==n&&(n=n.dehydrated,null!==n&&wt(n)))))}throw Error(s(163))}function yi(e,t){for(var n=e;;){if(5===n.tag){var a=n.stateNode;if(t)"function"==typeof(a=a.style).setProperty?a.setProperty("display","none","important"):a.display="none";else{a=n.stateNode;var r=n.memoizedProps.style;r=null!=r&&r.hasOwnProperty("display")?r.display:null,a.style.display=xe("display",r)}}else if(6===n.tag)n.stateNode.nodeValue=t?"":n.memoizedProps;else if((23!==n.tag&&24!==n.tag||null===n.memoizedState||n===e)&&null!==n.child){n.child.return=n,n=n.child;continue}if(n===e)break;for(;null===n.sibling;){if(null===n.return||n.return===e)return;n=n.return}n.sibling.return=n.return,n=n.sibling}}function vi(e,t){if(Er&&"function"==typeof Er.onCommitFiberUnmount)try{Er.onCommitFiberUnmount(Sr,t)}catch(o){}switch(t.tag){case 0:case 11:case 14:case 15:case 22:if(null!==(e=t.updateQueue)&&null!==(e=e.lastEffect)){var n=e=e.next;do{var a=n,r=a.destroy;if(a=a.tag,void 0!==r)if(4&a)Dl(t,n);else{a=t;try{r()}catch(o){jl(a,o)}}n=n.next}while(n!==e)}break;case 1:if(gi(t),"function"==typeof(e=t.stateNode).componentWillUnmount)try{e.props=t.memoizedProps,e.state=t.memoizedState,e.componentWillUnmount()}catch(o){jl(t,o)}break;case 5:gi(t);break;case 4:_i(e,t)}}function xi(e){e.alternate=null,e.child=null,e.dependencies=null,e.firstEffect=null,e.lastEffect=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.return=null,e.updateQueue=null}function wi(e){return 5===e.tag||3===e.tag||4===e.tag}function Si(e){e:{for(var t=e.return;null!==t;){if(wi(t))break e;t=t.return}throw Error(s(160))}var n=t;switch(t=n.stateNode,n.tag){case 5:var a=!1;break;case 3:case 4:t=t.containerInfo,a=!0;break;default:throw Error(s(161))}16&n.flags&&(be(t,""),n.flags&=-17);e:t:for(n=e;;){for(;null===n.sibling;){if(null===n.return||wi(n.return)){n=null;break e}n=n.return}for(n.sibling.return=n.return,n=n.sibling;5!==n.tag&&6!==n.tag&&18!==n.tag;){if(2&n.flags)continue t;if(null===n.child||4===n.tag)continue t;n.child.return=n,n=n.child}if(!(2&n.flags)){n=n.stateNode;break e}}a?Ei(e,n,t):ki(e,n,t)}function Ei(e,t,n){var a=e.tag,r=5===a||6===a;if(r)e=r?e.stateNode:e.stateNode.instance,t?8===n.nodeType?n.parentNode.insertBefore(e,t):n.insertBefore(e,t):(8===n.nodeType?(t=n.parentNode).insertBefore(e,n):(t=n).appendChild(e),null!=(n=n._reactRootContainer)||null!==t.onclick||(t.onclick=Ba));else if(4!==a&&null!==(e=e.child))for(Ei(e,t,n),e=e.sibling;null!==e;)Ei(e,t,n),e=e.sibling}function ki(e,t,n){var a=e.tag,r=5===a||6===a;if(r)e=r?e.stateNode:e.stateNode.instance,t?n.insertBefore(e,t):n.appendChild(e);else if(4!==a&&null!==(e=e.child))for(ki(e,t,n),e=e.sibling;null!==e;)ki(e,t,n),e=e.sibling}function _i(e,t){for(var n,a,r=t,o=!1;;){if(!o){o=r.return;e:for(;;){if(null===o)throw Error(s(160));switch(n=o.stateNode,o.tag){case 5:a=!1;break e;case 3:case 4:n=n.containerInfo,a=!0;break e}o=o.return}o=!0}if(5===r.tag||6===r.tag){e:for(var i=e,l=r,c=l;;)if(vi(i,c),null!==c.child&&4!==c.tag)c.child.return=c,c=c.child;else{if(c===l)break e;for(;null===c.sibling;){if(null===c.return||c.return===l)break e;c=c.return}c.sibling.return=c.return,c=c.sibling}a?(i=n,l=r.stateNode,8===i.nodeType?i.parentNode.removeChild(l):i.removeChild(l)):n.removeChild(r.stateNode)}else if(4===r.tag){if(null!==r.child){n=r.stateNode.containerInfo,a=!0,r.child.return=r,r=r.child;continue}}else if(vi(e,r),null!==r.child){r.child.return=r,r=r.child;continue}if(r===t)break;for(;null===r.sibling;){if(null===r.return||r.return===t)return;4===(r=r.return).tag&&(o=!1)}r.sibling.return=r.return,r=r.sibling}}function Ai(e,t){switch(t.tag){case 0:case 11:case 14:case 15:case 22:var n=t.updateQueue;if(null!==(n=null!==n?n.lastEffect:null)){var a=n=n.next;do{!(3&~a.tag)&&(e=a.destroy,a.destroy=void 0,void 0!==e&&e()),a=a.next}while(a!==n)}return;case 1:case 12:case 17:return;case 5:if(null!=(n=t.stateNode)){a=t.memoizedProps;var r=null!==e?e.memoizedProps:a;e=t.type;var o=t.updateQueue;if(t.updateQueue=null,null!==o){for(n[Za]=a,"input"===e&&"radio"===a.type&&null!=a.name&&te(n,a),ke(e,r),t=ke(e,a),r=0;r<o.length;r+=2){var i=o[r],l=o[r+1];"style"===i?we(n,l):"dangerouslySetInnerHTML"===i?he(n,l):"children"===i?be(n,l):x(n,i,l,t)}switch(e){case"input":ne(n,a);break;case"textarea":ce(n,a);break;case"select":e=n._wrapperState.wasMultiple,n._wrapperState.wasMultiple=!!a.multiple,null!=(o=a.value)?se(n,!!a.multiple,o,!1):e!==!!a.multiple&&(null!=a.defaultValue?se(n,!!a.multiple,a.defaultValue,!0):se(n,!!a.multiple,a.multiple?[]:"",!1))}}}return;case 6:if(null===t.stateNode)throw Error(s(162));return void(t.stateNode.nodeValue=t.memoizedProps);case 3:return void((n=t.stateNode).hydrate&&(n.hydrate=!1,wt(n.containerInfo)));case 13:return null!==t.memoizedState&&(Vi=$r(),yi(t.child,!0)),void Ci(t);case 19:return void Ci(t);case 23:case 24:return void yi(t,null!==t.memoizedState)}throw Error(s(163))}function Ci(e){var t=e.updateQueue;if(null!==t){e.updateQueue=null;var n=e.stateNode;null===n&&(n=e.stateNode=new mi),t.forEach((function(t){var a=$l.bind(null,e,t);n.has(t)||(n.add(t),t.then(a,a))}))}}function qi(e,t){return null!==e&&(null===(e=e.memoizedState)||null!==e.dehydrated)&&(null!==(t=t.memoizedState)&&null===t.dehydrated)}var Ti=Math.ceil,Ni=w.ReactCurrentDispatcher,Li=w.ReactCurrentOwner,Oi=0,Pi=null,Ri=null,Ii=0,Mi=0,Di=lr(0),Fi=0,Bi=null,ji=0,zi=0,$i=0,Ui=0,Hi=null,Vi=0,Gi=1/0;function Wi(){Gi=$r()+500}var Yi,Ki=null,Qi=!1,Xi=null,Zi=null,Ji=!1,el=null,tl=90,nl=[],al=[],rl=null,ol=0,sl=null,il=-1,ll=0,cl=0,ul=null,dl=!1;function fl(){return 48&Oi?$r():-1!==il?il:il=$r()}function pl(e){if(!(2&(e=e.mode)))return 1;if(!(4&e))return 99===Ur()?1:2;if(0===ll&&(ll=ji),0!==Kr.transition){0!==cl&&(cl=null!==Hi?Hi.pendingLanes:0),e=ll;var t=4186112&~cl;return 0===(t&=-t)&&(0===(t=(e=4186112&~e)&-e)&&(t=8192)),t}return e=Ur(),4&Oi&&98===e?e=Bt(12,ll):e=Bt(e=function(e){switch(e){case 99:return 15;case 98:return 10;case 97:case 96:return 8;case 95:return 2;default:return 0}}(e),ll),e}function ml(e,t,n){if(50<ol)throw ol=0,sl=null,Error(s(185));if(null===(e=gl(e,t)))return null;$t(e,t,n),e===Pi&&($i|=t,4===Fi&&yl(e,Ii));var a=Ur();1===t?8&Oi&&!(48&Oi)?vl(e):(hl(e,n),0===Oi&&(Wi(),Wr())):(!(4&Oi)||98!==a&&99!==a||(null===rl?rl=new Set([e]):rl.add(e)),hl(e,n)),Hi=e}function gl(e,t){e.lanes|=t;var n=e.alternate;for(null!==n&&(n.lanes|=t),n=e,e=e.return;null!==e;)e.childLanes|=t,null!==(n=e.alternate)&&(n.childLanes|=t),n=e,e=e.return;return 3===n.tag?n.stateNode:null}function hl(e,t){for(var n=e.callbackNode,a=e.suspendedLanes,r=e.pingedLanes,o=e.expirationTimes,i=e.pendingLanes;0<i;){var l=31-Ut(i),c=1<<l,u=o[l];if(-1===u){if(!(c&a)||c&r){u=t,Mt(c);var d=It;o[l]=10<=d?u+250:6<=d?u+5e3:-1}}else u<=t&&(e.expiredLanes|=c);i&=~c}if(a=Dt(e,e===Pi?Ii:0),t=It,0===a)null!==n&&(n!==Mr&&Ar(n),e.callbackNode=null,e.callbackPriority=0);else{if(null!==n){if(e.callbackPriority===t)return;n!==Mr&&Ar(n)}15===t?(n=vl.bind(null,e),null===Fr?(Fr=[n],Br=_r(Lr,Yr)):Fr.push(n),n=Mr):14===t?n=Gr(99,vl.bind(null,e)):(n=function(e){switch(e){case 15:case 14:return 99;case 13:case 12:case 11:case 10:return 98;case 9:case 8:case 7:case 6:case 4:case 5:return 97;case 3:case 2:case 1:return 95;case 0:return 90;default:throw Error(s(358,e))}}(t),n=Gr(n,bl.bind(null,e))),e.callbackPriority=t,e.callbackNode=n}}function bl(e){if(il=-1,cl=ll=0,48&Oi)throw Error(s(327));var t=e.callbackNode;if(Il()&&e.callbackNode!==t)return null;var n=Dt(e,e===Pi?Ii:0);if(0===n)return null;var a=n,r=Oi;Oi|=16;var o=Al();for(Pi===e&&Ii===a||(Wi(),kl(e,a));;)try{Tl();break}catch(l){_l(e,l)}if(to(),Ni.current=o,Oi=r,null!==Ri?a=0:(Pi=null,Ii=0,a=Fi),ji&$i)kl(e,0);else if(0!==a){if(2===a&&(Oi|=64,e.hydrate&&(e.hydrate=!1,Ga(e.containerInfo)),0!==(n=Ft(e))&&(a=Cl(e,n))),1===a)throw t=Bi,kl(e,0),yl(e,n),hl(e,$r()),t;switch(e.finishedWork=e.current.alternate,e.finishedLanes=n,a){case 0:case 1:throw Error(s(345));case 2:case 5:Ol(e);break;case 3:if(yl(e,n),(62914560&n)===n&&10<(a=Vi+500-$r())){if(0!==Dt(e,0))break;if(((r=e.suspendedLanes)&n)!==n){fl(),e.pingedLanes|=e.suspendedLanes&r;break}e.timeoutHandle=Ha(Ol.bind(null,e),a);break}Ol(e);break;case 4:if(yl(e,n),(4186112&n)===n)break;for(a=e.eventTimes,r=-1;0<n;){var i=31-Ut(n);o=1<<i,(i=a[i])>r&&(r=i),n&=~o}if(n=r,10<(n=(120>(n=$r()-n)?120:480>n?480:1080>n?1080:1920>n?1920:3e3>n?3e3:4320>n?4320:1960*Ti(n/1960))-n)){e.timeoutHandle=Ha(Ol.bind(null,e),n);break}Ol(e);break;default:throw Error(s(329))}}return hl(e,$r()),e.callbackNode===t?bl.bind(null,e):null}function yl(e,t){for(t&=~Ui,t&=~$i,e.suspendedLanes|=t,e.pingedLanes&=~t,e=e.expirationTimes;0<t;){var n=31-Ut(t),a=1<<n;e[n]=-1,t&=~a}}function vl(e){if(48&Oi)throw Error(s(327));if(Il(),e===Pi&&e.expiredLanes&Ii){var t=Ii,n=Cl(e,t);ji&$i&&(n=Cl(e,t=Dt(e,t)))}else n=Cl(e,t=Dt(e,0));if(0!==e.tag&&2===n&&(Oi|=64,e.hydrate&&(e.hydrate=!1,Ga(e.containerInfo)),0!==(t=Ft(e))&&(n=Cl(e,t))),1===n)throw n=Bi,kl(e,0),yl(e,t),hl(e,$r()),n;return e.finishedWork=e.current.alternate,e.finishedLanes=t,Ol(e),hl(e,$r()),null}function xl(e,t){var n=Oi;Oi|=1;try{return e(t)}finally{0===(Oi=n)&&(Wi(),Wr())}}function wl(e,t){var n=Oi;Oi&=-2,Oi|=8;try{return e(t)}finally{0===(Oi=n)&&(Wi(),Wr())}}function Sl(e,t){ur(Di,Mi),Mi|=t,ji|=t}function El(){Mi=Di.current,cr(Di)}function kl(e,t){e.finishedWork=null,e.finishedLanes=0;var n=e.timeoutHandle;if(-1!==n&&(e.timeoutHandle=-1,Va(n)),null!==Ri)for(n=Ri.return;null!==n;){var a=n;switch(a.tag){case 1:null!=(a=a.type.childContextTypes)&&br();break;case 3:Ro(),cr(pr),cr(fr),Ko();break;case 5:Mo(a);break;case 4:Ro();break;case 13:case 19:cr(Do);break;case 10:no(a);break;case 23:case 24:El()}n=n.return}Pi=e,Ri=Gl(e.current,null),Ii=Mi=ji=t,Fi=0,Bi=null,Ui=$i=zi=0}function _l(e,t){for(;;){var n=Ri;try{if(to(),Qo.current=Ls,ns){for(var a=Jo.memoizedState;null!==a;){var r=a.queue;null!==r&&(r.pending=null),a=a.next}ns=!1}if(Zo=0,ts=es=Jo=null,as=!1,Li.current=null,null===n||null===n.return){Fi=1,Bi=t,Ri=null;break}e:{var o=e,s=n.return,i=n,l=t;if(t=Ii,i.flags|=2048,i.firstEffect=i.lastEffect=null,null!==l&&"object"==typeof l&&"function"==typeof l.then){var c=l;if(!(2&i.mode)){var u=i.alternate;u?(i.updateQueue=u.updateQueue,i.memoizedState=u.memoizedState,i.lanes=u.lanes):(i.updateQueue=null,i.memoizedState=null)}var d=!!(1&Do.current),f=s;do{var p;if(p=13===f.tag){var m=f.memoizedState;if(null!==m)p=null!==m.dehydrated;else{var g=f.memoizedProps;p=void 0!==g.fallback&&(!0!==g.unstable_avoidThisFallback||!d)}}if(p){var h=f.updateQueue;if(null===h){var b=new Set;b.add(c),f.updateQueue=b}else h.add(c);if(!(2&f.mode)){if(f.flags|=64,i.flags|=16384,i.flags&=-2981,1===i.tag)if(null===i.alternate)i.tag=17;else{var y=co(-1,1);y.tag=2,uo(i,y)}i.lanes|=1;break e}l=void 0,i=t;var v=o.pingCache;if(null===v?(v=o.pingCache=new di,l=new Set,v.set(c,l)):void 0===(l=v.get(c))&&(l=new Set,v.set(c,l)),!l.has(i)){l.add(i);var x=zl.bind(null,o,c,i);c.then(x,x)}f.flags|=4096,f.lanes=t;break e}f=f.return}while(null!==f);l=Error((W(i.type)||"A React component")+" suspended while rendering, but no fallback UI was specified.\n\nAdd a <Suspense fallback=...> component higher in the tree to provide a loading indicator or placeholder to display.")}5!==Fi&&(Fi=2),l=ci(l,i),f=s;do{switch(f.tag){case 3:o=l,f.flags|=4096,t&=-t,f.lanes|=t,fo(f,fi(0,o,t));break e;case 1:o=l;var w=f.type,S=f.stateNode;if(!(64&f.flags||"function"!=typeof w.getDerivedStateFromError&&(null===S||"function"!=typeof S.componentDidCatch||null!==Zi&&Zi.has(S)))){f.flags|=4096,t&=-t,f.lanes|=t,fo(f,pi(f,o,t));break e}}f=f.return}while(null!==f)}Ll(n)}catch(E){t=E,Ri===n&&null!==n&&(Ri=n=n.return);continue}break}}function Al(){var e=Ni.current;return Ni.current=Ls,null===e?Ls:e}function Cl(e,t){var n=Oi;Oi|=16;var a=Al();for(Pi===e&&Ii===t||kl(e,t);;)try{ql();break}catch(r){_l(e,r)}if(to(),Oi=n,Ni.current=a,null!==Ri)throw Error(s(261));return Pi=null,Ii=0,Fi}function ql(){for(;null!==Ri;)Nl(Ri)}function Tl(){for(;null!==Ri&&!Cr();)Nl(Ri)}function Nl(e){var t=Yi(e.alternate,e,Mi);e.memoizedProps=e.pendingProps,null===t?Ll(e):Ri=t,Li.current=null}function Ll(e){var t=e;do{var n=t.alternate;if(e=t.return,2048&t.flags){if(null!==(n=li(t)))return n.flags&=2047,void(Ri=n);null!==e&&(e.firstEffect=e.lastEffect=null,e.flags|=2048)}else{if(null!==(n=ii(n,t,Mi)))return void(Ri=n);if(24!==(n=t).tag&&23!==n.tag||null===n.memoizedState||1073741824&Mi||!(4&n.mode)){for(var a=0,r=n.child;null!==r;)a|=r.lanes|r.childLanes,r=r.sibling;n.childLanes=a}null!==e&&!(2048&e.flags)&&(null===e.firstEffect&&(e.firstEffect=t.firstEffect),null!==t.lastEffect&&(null!==e.lastEffect&&(e.lastEffect.nextEffect=t.firstEffect),e.lastEffect=t.lastEffect),1<t.flags&&(null!==e.lastEffect?e.lastEffect.nextEffect=t:e.firstEffect=t,e.lastEffect=t))}if(null!==(t=t.sibling))return void(Ri=t);Ri=t=e}while(null!==t);0===Fi&&(Fi=5)}function Ol(e){var t=Ur();return Vr(99,Pl.bind(null,e,t)),null}function Pl(e,t){do{Il()}while(null!==el);if(48&Oi)throw Error(s(327));var n=e.finishedWork;if(null===n)return null;if(e.finishedWork=null,e.finishedLanes=0,n===e.current)throw Error(s(177));e.callbackNode=null;var a=n.lanes|n.childLanes,r=a,o=e.pendingLanes&~r;e.pendingLanes=r,e.suspendedLanes=0,e.pingedLanes=0,e.expiredLanes&=r,e.mutableReadLanes&=r,e.entangledLanes&=r,r=e.entanglements;for(var i=e.eventTimes,l=e.expirationTimes;0<o;){var c=31-Ut(o),u=1<<c;r[c]=0,i[c]=-1,l[c]=-1,o&=~u}if(null!==rl&&!(24&a)&&rl.has(e)&&rl.delete(e),e===Pi&&(Ri=Pi=null,Ii=0),1<n.flags?null!==n.lastEffect?(n.lastEffect.nextEffect=n,a=n.firstEffect):a=n:a=n.firstEffect,null!==a){if(r=Oi,Oi|=32,Li.current=null,ja=Yt,ha(i=ga())){if("selectionStart"in i)l={start:i.selectionStart,end:i.selectionEnd};else e:if(l=(l=i.ownerDocument)&&l.defaultView||window,(u=l.getSelection&&l.getSelection())&&0!==u.rangeCount){l=u.anchorNode,o=u.anchorOffset,c=u.focusNode,u=u.focusOffset;try{l.nodeType,c.nodeType}catch(A){l=null;break e}var d=0,f=-1,p=-1,m=0,g=0,h=i,b=null;t:for(;;){for(var y;h!==l||0!==o&&3!==h.nodeType||(f=d+o),h!==c||0!==u&&3!==h.nodeType||(p=d+u),3===h.nodeType&&(d+=h.nodeValue.length),null!==(y=h.firstChild);)b=h,h=y;for(;;){if(h===i)break t;if(b===l&&++m===o&&(f=d),b===c&&++g===u&&(p=d),null!==(y=h.nextSibling))break;b=(h=b).parentNode}h=y}l=-1===f||-1===p?null:{start:f,end:p}}else l=null;l=l||{start:0,end:0}}else l=null;za={focusedElem:i,selectionRange:l},Yt=!1,ul=null,dl=!1,Ki=a;do{try{Rl()}catch(A){if(null===Ki)throw Error(s(330));jl(Ki,A),Ki=Ki.nextEffect}}while(null!==Ki);ul=null,Ki=a;do{try{for(i=e;null!==Ki;){var v=Ki.flags;if(16&v&&be(Ki.stateNode,""),128&v){var x=Ki.alternate;if(null!==x){var w=x.ref;null!==w&&("function"==typeof w?w(null):w.current=null)}}switch(1038&v){case 2:Si(Ki),Ki.flags&=-3;break;case 6:Si(Ki),Ki.flags&=-3,Ai(Ki.alternate,Ki);break;case 1024:Ki.flags&=-1025;break;case 1028:Ki.flags&=-1025,Ai(Ki.alternate,Ki);break;case 4:Ai(Ki.alternate,Ki);break;case 8:_i(i,l=Ki);var S=l.alternate;xi(l),null!==S&&xi(S)}Ki=Ki.nextEffect}}catch(A){if(null===Ki)throw Error(s(330));jl(Ki,A),Ki=Ki.nextEffect}}while(null!==Ki);if(w=za,x=ga(),v=w.focusedElem,i=w.selectionRange,x!==v&&v&&v.ownerDocument&&ma(v.ownerDocument.documentElement,v)){null!==i&&ha(v)&&(x=i.start,void 0===(w=i.end)&&(w=x),"selectionStart"in v?(v.selectionStart=x,v.selectionEnd=Math.min(w,v.value.length)):(w=(x=v.ownerDocument||document)&&x.defaultView||window).getSelection&&(w=w.getSelection(),l=v.textContent.length,S=Math.min(i.start,l),i=void 0===i.end?S:Math.min(i.end,l),!w.extend&&S>i&&(l=i,i=S,S=l),l=pa(v,S),o=pa(v,i),l&&o&&(1!==w.rangeCount||w.anchorNode!==l.node||w.anchorOffset!==l.offset||w.focusNode!==o.node||w.focusOffset!==o.offset)&&((x=x.createRange()).setStart(l.node,l.offset),w.removeAllRanges(),S>i?(w.addRange(x),w.extend(o.node,o.offset)):(x.setEnd(o.node,o.offset),w.addRange(x))))),x=[];for(w=v;w=w.parentNode;)1===w.nodeType&&x.push({element:w,left:w.scrollLeft,top:w.scrollTop});for("function"==typeof v.focus&&v.focus(),v=0;v<x.length;v++)(w=x[v]).element.scrollLeft=w.left,w.element.scrollTop=w.top}Yt=!!ja,za=ja=null,e.current=n,Ki=a;do{try{for(v=e;null!==Ki;){var E=Ki.flags;if(36&E&&bi(v,Ki.alternate,Ki),128&E){x=void 0;var k=Ki.ref;if(null!==k){var _=Ki.stateNode;Ki.tag,x=_,"function"==typeof k?k(x):k.current=x}}Ki=Ki.nextEffect}}catch(A){if(null===Ki)throw Error(s(330));jl(Ki,A),Ki=Ki.nextEffect}}while(null!==Ki);Ki=null,Dr(),Oi=r}else e.current=n;if(Ji)Ji=!1,el=e,tl=t;else for(Ki=a;null!==Ki;)t=Ki.nextEffect,Ki.nextEffect=null,8&Ki.flags&&((E=Ki).sibling=null,E.stateNode=null),Ki=t;if(0===(a=e.pendingLanes)&&(Zi=null),1===a?e===sl?ol++:(ol=0,sl=e):ol=0,n=n.stateNode,Er&&"function"==typeof Er.onCommitFiberRoot)try{Er.onCommitFiberRoot(Sr,n,void 0,!(64&~n.current.flags))}catch(A){}if(hl(e,$r()),Qi)throw Qi=!1,e=Xi,Xi=null,e;return 8&Oi||Wr(),null}function Rl(){for(;null!==Ki;){var e=Ki.alternate;dl||null===ul||(8&Ki.flags?Je(Ki,ul)&&(dl=!0):13===Ki.tag&&qi(e,Ki)&&Je(Ki,ul)&&(dl=!0));var t=Ki.flags;256&t&&hi(e,Ki),!(512&t)||Ji||(Ji=!0,Gr(97,(function(){return Il(),null}))),Ki=Ki.nextEffect}}function Il(){if(90!==tl){var e=97<tl?97:tl;return tl=90,Vr(e,Fl)}return!1}function Ml(e,t){nl.push(t,e),Ji||(Ji=!0,Gr(97,(function(){return Il(),null})))}function Dl(e,t){al.push(t,e),Ji||(Ji=!0,Gr(97,(function(){return Il(),null})))}function Fl(){if(null===el)return!1;var e=el;if(el=null,48&Oi)throw Error(s(331));var t=Oi;Oi|=32;var n=al;al=[];for(var a=0;a<n.length;a+=2){var r=n[a],o=n[a+1],i=r.destroy;if(r.destroy=void 0,"function"==typeof i)try{i()}catch(c){if(null===o)throw Error(s(330));jl(o,c)}}for(n=nl,nl=[],a=0;a<n.length;a+=2){r=n[a],o=n[a+1];try{var l=r.create;r.destroy=l()}catch(c){if(null===o)throw Error(s(330));jl(o,c)}}for(l=e.current.firstEffect;null!==l;)e=l.nextEffect,l.nextEffect=null,8&l.flags&&(l.sibling=null,l.stateNode=null),l=e;return Oi=t,Wr(),!0}function Bl(e,t,n){uo(e,t=fi(0,t=ci(n,t),1)),t=fl(),null!==(e=gl(e,1))&&($t(e,1,t),hl(e,t))}function jl(e,t){if(3===e.tag)Bl(e,e,t);else for(var n=e.return;null!==n;){if(3===n.tag){Bl(n,e,t);break}if(1===n.tag){var a=n.stateNode;if("function"==typeof n.type.getDerivedStateFromError||"function"==typeof a.componentDidCatch&&(null===Zi||!Zi.has(a))){var r=pi(n,e=ci(t,e),1);if(uo(n,r),r=fl(),null!==(n=gl(n,1)))$t(n,1,r),hl(n,r);else if("function"==typeof a.componentDidCatch&&(null===Zi||!Zi.has(a)))try{a.componentDidCatch(t,e)}catch(o){}break}}n=n.return}}function zl(e,t,n){var a=e.pingCache;null!==a&&a.delete(t),t=fl(),e.pingedLanes|=e.suspendedLanes&n,Pi===e&&(Ii&n)===n&&(4===Fi||3===Fi&&(62914560&Ii)===Ii&&500>$r()-Vi?kl(e,0):Ui|=n),hl(e,t)}function $l(e,t){var n=e.stateNode;null!==n&&n.delete(t),0===(t=0)&&(2&(t=e.mode)?4&t?(0===ll&&(ll=ji),0===(t=jt(62914560&~ll))&&(t=4194304)):t=99===Ur()?1:2:t=1),n=fl(),null!==(e=gl(e,t))&&($t(e,t,n),hl(e,n))}function Ul(e,t,n,a){this.tag=e,this.key=n,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=t,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=a,this.flags=0,this.lastEffect=this.firstEffect=this.nextEffect=null,this.childLanes=this.lanes=0,this.alternate=null}function Hl(e,t,n,a){return new Ul(e,t,n,a)}function Vl(e){return!(!(e=e.prototype)||!e.isReactComponent)}function Gl(e,t){var n=e.alternate;return null===n?((n=Hl(e.tag,t,e.key,e.mode)).elementType=e.elementType,n.type=e.type,n.stateNode=e.stateNode,n.alternate=e,e.alternate=n):(n.pendingProps=t,n.type=e.type,n.flags=0,n.nextEffect=null,n.firstEffect=null,n.lastEffect=null),n.childLanes=e.childLanes,n.lanes=e.lanes,n.child=e.child,n.memoizedProps=e.memoizedProps,n.memoizedState=e.memoizedState,n.updateQueue=e.updateQueue,t=e.dependencies,n.dependencies=null===t?null:{lanes:t.lanes,firstContext:t.firstContext},n.sibling=e.sibling,n.index=e.index,n.ref=e.ref,n}function Wl(e,t,n,a,r,o){var i=2;if(a=e,"function"==typeof e)Vl(e)&&(i=1);else if("string"==typeof e)i=5;else e:switch(e){case k:return Yl(n.children,r,o,t);case M:i=8,r|=16;break;case _:i=8,r|=1;break;case A:return(e=Hl(12,n,t,8|r)).elementType=A,e.type=A,e.lanes=o,e;case N:return(e=Hl(13,n,t,r)).type=N,e.elementType=N,e.lanes=o,e;case L:return(e=Hl(19,n,t,r)).elementType=L,e.lanes=o,e;case D:return Kl(n,r,o,t);case F:return(e=Hl(24,n,t,r)).elementType=F,e.lanes=o,e;default:if("object"==typeof e&&null!==e)switch(e.$$typeof){case C:i=10;break e;case q:i=9;break e;case T:i=11;break e;case O:i=14;break e;case P:i=16,a=null;break e;case R:i=22;break e}throw Error(s(130,null==e?e:typeof e,""))}return(t=Hl(i,n,t,r)).elementType=e,t.type=a,t.lanes=o,t}function Yl(e,t,n,a){return(e=Hl(7,e,a,t)).lanes=n,e}function Kl(e,t,n,a){return(e=Hl(23,e,a,t)).elementType=D,e.lanes=n,e}function Ql(e,t,n){return(e=Hl(6,e,null,t)).lanes=n,e}function Xl(e,t,n){return(t=Hl(4,null!==e.children?e.children:[],e.key,t)).lanes=n,t.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},t}function Zl(e,t,n){this.tag=t,this.containerInfo=e,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.pendingContext=this.context=null,this.hydrate=n,this.callbackNode=null,this.callbackPriority=0,this.eventTimes=zt(0),this.expirationTimes=zt(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=zt(0),this.mutableSourceEagerHydrationData=null}function Jl(e,t,n,a){var r=t.current,o=fl(),i=pl(r);e:if(n){t:{if(Ke(n=n._reactInternals)!==n||1!==n.tag)throw Error(s(170));var l=n;do{switch(l.tag){case 3:l=l.stateNode.context;break t;case 1:if(hr(l.type)){l=l.stateNode.__reactInternalMemoizedMergedChildContext;break t}}l=l.return}while(null!==l);throw Error(s(171))}if(1===n.tag){var c=n.type;if(hr(c)){n=vr(n,c,l);break e}}n=l}else n=dr;return null===t.context?t.context=n:t.pendingContext=n,(t=co(o,i)).payload={element:e},null!==(a=void 0===a?null:a)&&(t.callback=a),uo(r,t),ml(r,i,o),i}function ec(e){return(e=e.current).child?(e.child.tag,e.child.stateNode):null}function tc(e,t){if(null!==(e=e.memoizedState)&&null!==e.dehydrated){var n=e.retryLane;e.retryLane=0!==n&&n<t?n:t}}function nc(e,t){tc(e,t),(e=e.alternate)&&tc(e,t)}function ac(e,t,n){var a=null!=n&&null!=n.hydrationOptions&&n.hydrationOptions.mutableSources||null;if(n=new Zl(e,t,null!=n&&!0===n.hydrate),t=Hl(3,null,null,2===t?7:1===t?3:0),n.current=t,t.stateNode=n,io(t),e[Ja]=n.current,La(8===e.nodeType?e.parentNode:e),a)for(e=0;e<a.length;e++){var r=(t=a[e])._getVersion;r=r(t._source),null==n.mutableSourceEagerHydrationData?n.mutableSourceEagerHydrationData=[t,r]:n.mutableSourceEagerHydrationData.push(t,r)}this._internalRoot=n}function rc(e){return!(!e||1!==e.nodeType&&9!==e.nodeType&&11!==e.nodeType&&(8!==e.nodeType||" react-mount-point-unstable "!==e.nodeValue))}function oc(e,t,n,a,r){var o=n._reactRootContainer;if(o){var s=o._internalRoot;if("function"==typeof r){var i=r;r=function(){var e=ec(s);i.call(e)}}Jl(t,s,e,r)}else{if(o=n._reactRootContainer=function(e,t){if(t||(t=!(!(t=e?9===e.nodeType?e.documentElement:e.firstChild:null)||1!==t.nodeType||!t.hasAttribute("data-reactroot"))),!t)for(var n;n=e.lastChild;)e.removeChild(n);return new ac(e,0,t?{hydrate:!0}:void 0)}(n,a),s=o._internalRoot,"function"==typeof r){var l=r;r=function(){var e=ec(s);l.call(e)}}wl((function(){Jl(t,s,e,r)}))}return ec(s)}function sc(e,t){var n=2<arguments.length&&void 0!==arguments[2]?arguments[2]:null;if(!rc(t))throw Error(s(200));return function(e,t,n){var a=3<arguments.length&&void 0!==arguments[3]?arguments[3]:null;return{$$typeof:E,key:null==a?null:""+a,children:e,containerInfo:t,implementation:n}}(e,t,null,n)}Yi=function(e,t,n){var a=t.lanes;if(null!==e)if(e.memoizedProps!==t.pendingProps||pr.current)Ms=!0;else{if(!(n&a)){switch(Ms=!1,t.tag){case 3:Gs(t),Wo();break;case 5:Io(t);break;case 1:hr(t.type)&&xr(t);break;case 4:Po(t,t.stateNode.containerInfo);break;case 10:a=t.memoizedProps.value;var r=t.type._context;ur(Xr,r._currentValue),r._currentValue=a;break;case 13:if(null!==t.memoizedState)return n&t.child.childLanes?Zs(e,t,n):(ur(Do,1&Do.current),null!==(t=oi(e,t,n))?t.sibling:null);ur(Do,1&Do.current);break;case 19:if(a=!!(n&t.childLanes),64&e.flags){if(a)return ri(e,t,n);t.flags|=64}if(null!==(r=t.memoizedState)&&(r.rendering=null,r.tail=null,r.lastEffect=null),ur(Do,Do.current),a)break;return null;case 23:case 24:return t.lanes=0,zs(e,t,n)}return oi(e,t,n)}Ms=!!(16384&e.flags)}else Ms=!1;switch(t.lanes=0,t.tag){case 2:if(a=t.type,null!==e&&(e.alternate=null,t.alternate=null,t.flags|=2),e=t.pendingProps,r=gr(t,fr.current),ro(t,n),r=ss(null,t,a,e,r,n),t.flags|=1,"object"==typeof r&&null!==r&&"function"==typeof r.render&&void 0===r.$$typeof){if(t.tag=1,t.memoizedState=null,t.updateQueue=null,hr(a)){var o=!0;xr(t)}else o=!1;t.memoizedState=null!==r.state&&void 0!==r.state?r.state:null,io(t);var i=a.getDerivedStateFromProps;"function"==typeof i&&ho(t,a,i,e),r.updater=bo,t.stateNode=r,r._reactInternals=t,wo(t,a,e,n),t=Vs(null,t,a,!0,o,n)}else t.tag=0,Ds(null,t,r,n),t=t.child;return t;case 16:r=t.elementType;e:{switch(null!==e&&(e.alternate=null,t.alternate=null,t.flags|=2),e=t.pendingProps,r=(o=r._init)(r._payload),t.type=r,o=t.tag=function(e){if("function"==typeof e)return Vl(e)?1:0;if(null!=e){if((e=e.$$typeof)===T)return 11;if(e===O)return 14}return 2}(r),e=Qr(r,e),o){case 0:t=Us(null,t,r,e,n);break e;case 1:t=Hs(null,t,r,e,n);break e;case 11:t=Fs(null,t,r,e,n);break e;case 14:t=Bs(null,t,r,Qr(r.type,e),a,n);break e}throw Error(s(306,r,""))}return t;case 0:return a=t.type,r=t.pendingProps,Us(e,t,a,r=t.elementType===a?r:Qr(a,r),n);case 1:return a=t.type,r=t.pendingProps,Hs(e,t,a,r=t.elementType===a?r:Qr(a,r),n);case 3:if(Gs(t),a=t.updateQueue,null===e||null===a)throw Error(s(282));if(a=t.pendingProps,r=null!==(r=t.memoizedState)?r.element:null,lo(e,t),po(t,a,null,n),(a=t.memoizedState.element)===r)Wo(),t=oi(e,t,n);else{if((o=(r=t.stateNode).hydrate)&&(jo=Wa(t.stateNode.containerInfo.firstChild),Bo=t,o=zo=!0),o){if(null!=(e=r.mutableSourceEagerHydrationData))for(r=0;r<e.length;r+=2)(o=e[r])._workInProgressVersionPrimary=e[r+1],Yo.push(o);for(n=Co(t,null,a,n),t.child=n;n;)n.flags=-3&n.flags|1024,n=n.sibling}else Ds(e,t,a,n),Wo();t=t.child}return t;case 5:return Io(t),null===e&&Ho(t),a=t.type,r=t.pendingProps,o=null!==e?e.memoizedProps:null,i=r.children,Ua(a,r)?i=null:null!==o&&Ua(a,o)&&(t.flags|=16),$s(e,t),Ds(e,t,i,n),t.child;case 6:return null===e&&Ho(t),null;case 13:return Zs(e,t,n);case 4:return Po(t,t.stateNode.containerInfo),a=t.pendingProps,null===e?t.child=Ao(t,null,a,n):Ds(e,t,a,n),t.child;case 11:return a=t.type,r=t.pendingProps,Fs(e,t,a,r=t.elementType===a?r:Qr(a,r),n);case 7:return Ds(e,t,t.pendingProps,n),t.child;case 8:case 12:return Ds(e,t,t.pendingProps.children,n),t.child;case 10:e:{a=t.type._context,r=t.pendingProps,i=t.memoizedProps,o=r.value;var l=t.type._context;if(ur(Xr,l._currentValue),l._currentValue=o,null!==i)if(l=i.value,0===(o=ca(l,o)?0:0|("function"==typeof a._calculateChangedBits?a._calculateChangedBits(l,o):1073741823))){if(i.children===r.children&&!pr.current){t=oi(e,t,n);break e}}else for(null!==(l=t.child)&&(l.return=t);null!==l;){var c=l.dependencies;if(null!==c){i=l.child;for(var u=c.firstContext;null!==u;){if(u.context===a&&u.observedBits&o){1===l.tag&&((u=co(-1,n&-n)).tag=2,uo(l,u)),l.lanes|=n,null!==(u=l.alternate)&&(u.lanes|=n),ao(l.return,n),c.lanes|=n;break}u=u.next}}else i=10===l.tag&&l.type===t.type?null:l.child;if(null!==i)i.return=l;else for(i=l;null!==i;){if(i===t){i=null;break}if(null!==(l=i.sibling)){l.return=i.return,i=l;break}i=i.return}l=i}Ds(e,t,r.children,n),t=t.child}return t;case 9:return r=t.type,a=(o=t.pendingProps).children,ro(t,n),a=a(r=oo(r,o.unstable_observedBits)),t.flags|=1,Ds(e,t,a,n),t.child;case 14:return o=Qr(r=t.type,t.pendingProps),Bs(e,t,r,o=Qr(r.type,o),a,n);case 15:return js(e,t,t.type,t.pendingProps,a,n);case 17:return a=t.type,r=t.pendingProps,r=t.elementType===a?r:Qr(a,r),null!==e&&(e.alternate=null,t.alternate=null,t.flags|=2),t.tag=1,hr(a)?(e=!0,xr(t)):e=!1,ro(t,n),vo(t,a,r),wo(t,a,r,n),Vs(null,t,a,!0,e,n);case 19:return ri(e,t,n);case 23:case 24:return zs(e,t,n)}throw Error(s(156,t.tag))},ac.prototype.render=function(e){Jl(e,this._internalRoot,null,null)},ac.prototype.unmount=function(){var e=this._internalRoot,t=e.containerInfo;Jl(null,e,null,(function(){t[Ja]=null}))},et=function(e){13===e.tag&&(ml(e,4,fl()),nc(e,4))},tt=function(e){13===e.tag&&(ml(e,67108864,fl()),nc(e,67108864))},nt=function(e){if(13===e.tag){var t=fl(),n=pl(e);ml(e,n,t),nc(e,n)}},at=function(e,t){return t()},Ae=function(e,t,n){switch(t){case"input":if(ne(e,n),t=n.name,"radio"===n.type&&null!=t){for(n=e;n.parentNode;)n=n.parentNode;for(n=n.querySelectorAll("input[name="+JSON.stringify(""+t)+'][type="radio"]'),t=0;t<n.length;t++){var a=n[t];if(a!==e&&a.form===e.form){var r=rr(a);if(!r)throw Error(s(90));X(a),ne(a,r)}}}break;case"textarea":ce(e,n);break;case"select":null!=(t=n.value)&&se(e,!!n.multiple,t,!1)}},Oe=xl,Pe=function(e,t,n,a,r){var o=Oi;Oi|=4;try{return Vr(98,e.bind(null,t,n,a,r))}finally{0===(Oi=o)&&(Wi(),Wr())}},Re=function(){!(49&Oi)&&(function(){if(null!==rl){var e=rl;rl=null,e.forEach((function(e){e.expiredLanes|=24&e.pendingLanes,hl(e,$r())}))}Wr()}(),Il())},Ie=function(e,t){var n=Oi;Oi|=2;try{return e(t)}finally{0===(Oi=n)&&(Wi(),Wr())}};var ic={Events:[nr,ar,rr,Ne,Le,Il,{current:!1}]},lc={findFiberByHostInstance:tr,bundleType:0,version:"17.0.2",rendererPackageName:"react-dom"},cc={bundleType:lc.bundleType,version:lc.version,rendererPackageName:lc.rendererPackageName,rendererConfig:lc.rendererConfig,overrideHookState:null,overrideHookStateDeletePath:null,overrideHookStateRenamePath:null,overrideProps:null,overridePropsDeletePath:null,overridePropsRenamePath:null,setSuspenseHandler:null,scheduleUpdate:null,currentDispatcherRef:w.ReactCurrentDispatcher,findHostInstanceByFiber:function(e){return null===(e=Ze(e))?null:e.stateNode},findFiberByHostInstance:lc.findFiberByHostInstance||function(){return null},findHostInstancesForRefresh:null,scheduleRefresh:null,scheduleRoot:null,setRefreshHandler:null,getCurrentFiber:null};if("undefined"!=typeof __REACT_DEVTOOLS_GLOBAL_HOOK__){var uc=__REACT_DEVTOOLS_GLOBAL_HOOK__;if(!uc.isDisabled&&uc.supportsFiber)try{Sr=uc.inject(cc),Er=uc}catch(ge){}}t.hydrate=function(e,t,n){if(!rc(t))throw Error(s(200));return oc(null,e,t,!0,n)}},961:(e,t,n)=>{"use strict";!function e(){if("undefined"!=typeof __REACT_DEVTOOLS_GLOBAL_HOOK__&&"function"==typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE)try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(e)}catch(t){console.error(t)}}(),e.exports=n(2551)},115:e=>{var t="undefined"!=typeof Element,n="function"==typeof Map,a="function"==typeof Set,r="function"==typeof ArrayBuffer&&!!ArrayBuffer.isView;function o(e,s){if(e===s)return!0;if(e&&s&&"object"==typeof e&&"object"==typeof s){if(e.constructor!==s.constructor)return!1;var i,l,c,u;if(Array.isArray(e)){if((i=e.length)!=s.length)return!1;for(l=i;0!=l--;)if(!o(e[l],s[l]))return!1;return!0}if(n&&e instanceof Map&&s instanceof Map){if(e.size!==s.size)return!1;for(u=e.entries();!(l=u.next()).done;)if(!s.has(l.value[0]))return!1;for(u=e.entries();!(l=u.next()).done;)if(!o(l.value[1],s.get(l.value[0])))return!1;return!0}if(a&&e instanceof Set&&s instanceof Set){if(e.size!==s.size)return!1;for(u=e.entries();!(l=u.next()).done;)if(!s.has(l.value[0]))return!1;return!0}if(r&&ArrayBuffer.isView(e)&&ArrayBuffer.isView(s)){if((i=e.length)!=s.length)return!1;for(l=i;0!=l--;)if(e[l]!==s[l])return!1;return!0}if(e.constructor===RegExp)return e.source===s.source&&e.flags===s.flags;if(e.valueOf!==Object.prototype.valueOf&&"function"==typeof e.valueOf&&"function"==typeof s.valueOf)return e.valueOf()===s.valueOf();if(e.toString!==Object.prototype.toString&&"function"==typeof e.toString&&"function"==typeof s.toString)return e.toString()===s.toString();if((i=(c=Object.keys(e)).length)!==Object.keys(s).length)return!1;for(l=i;0!=l--;)if(!Object.prototype.hasOwnProperty.call(s,c[l]))return!1;if(t&&e instanceof Element)return!1;for(l=i;0!=l--;)if(("_owner"!==c[l]&&"__v"!==c[l]&&"__o"!==c[l]||!e.$$typeof)&&!o(e[c[l]],s[c[l]]))return!1;return!0}return e!=e&&s!=s}e.exports=function(e,t){try{return o(e,t)}catch(n){if((n.message||"").match(/stack|recursion/i))return console.warn("react-fast-compare cannot handle circular refs"),!1;throw n}}},545:(e,t,n)=>{"use strict";n.d(t,{mg:()=>J,vd:()=>V});var a=n(6540),r=n(5556),o=n.n(r),s=n(115),i=n.n(s),l=n(311),c=n.n(l),u=n(2833),d=n.n(u);function f(){return f=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var a in n)Object.prototype.hasOwnProperty.call(n,a)&&(e[a]=n[a])}return e},f.apply(this,arguments)}function p(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,m(e,t)}function m(e,t){return m=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e},m(e,t)}function g(e,t){if(null==e)return{};var n,a,r={},o=Object.keys(e);for(a=0;a<o.length;a++)t.indexOf(n=o[a])>=0||(r[n]=e[n]);return r}var h={BASE:"base",BODY:"body",HEAD:"head",HTML:"html",LINK:"link",META:"meta",NOSCRIPT:"noscript",SCRIPT:"script",STYLE:"style",TITLE:"title",FRAGMENT:"Symbol(react.fragment)"},b={rel:["amphtml","canonical","alternate"]},y={type:["application/ld+json"]},v={charset:"",name:["robots","description"],property:["og:type","og:title","og:url","og:image","og:image:alt","og:description","twitter:url","twitter:title","twitter:description","twitter:image","twitter:image:alt","twitter:card","twitter:site"]},x=Object.keys(h).map((function(e){return h[e]})),w={accesskey:"accessKey",charset:"charSet",class:"className",contenteditable:"contentEditable",contextmenu:"contextMenu","http-equiv":"httpEquiv",itemprop:"itemProp",tabindex:"tabIndex"},S=Object.keys(w).reduce((function(e,t){return e[w[t]]=t,e}),{}),E=function(e,t){for(var n=e.length-1;n>=0;n-=1){var a=e[n];if(Object.prototype.hasOwnProperty.call(a,t))return a[t]}return null},k=function(e){var t=E(e,h.TITLE),n=E(e,"titleTemplate");if(Array.isArray(t)&&(t=t.join("")),n&&t)return n.replace(/%s/g,(function(){return t}));var a=E(e,"defaultTitle");return t||a||void 0},_=function(e){return E(e,"onChangeClientState")||function(){}},A=function(e,t){return t.filter((function(t){return void 0!==t[e]})).map((function(t){return t[e]})).reduce((function(e,t){return f({},e,t)}),{})},C=function(e,t){return t.filter((function(e){return void 0!==e[h.BASE]})).map((function(e){return e[h.BASE]})).reverse().reduce((function(t,n){if(!t.length)for(var a=Object.keys(n),r=0;r<a.length;r+=1){var o=a[r].toLowerCase();if(-1!==e.indexOf(o)&&n[o])return t.concat(n)}return t}),[])},q=function(e,t,n){var a={};return n.filter((function(t){return!!Array.isArray(t[e])||(void 0!==t[e]&&console&&"function"==typeof console.warn&&console.warn("Helmet: "+e+' should be of type "Array". Instead found type "'+typeof t[e]+'"'),!1)})).map((function(t){return t[e]})).reverse().reduce((function(e,n){var r={};n.filter((function(e){for(var n,o=Object.keys(e),s=0;s<o.length;s+=1){var i=o[s],l=i.toLowerCase();-1===t.indexOf(l)||"rel"===n&&"canonical"===e[n].toLowerCase()||"rel"===l&&"stylesheet"===e[l].toLowerCase()||(n=l),-1===t.indexOf(i)||"innerHTML"!==i&&"cssText"!==i&&"itemprop"!==i||(n=i)}if(!n||!e[n])return!1;var c=e[n].toLowerCase();return a[n]||(a[n]={}),r[n]||(r[n]={}),!a[n][c]&&(r[n][c]=!0,!0)})).reverse().forEach((function(t){return e.push(t)}));for(var o=Object.keys(r),s=0;s<o.length;s+=1){var i=o[s],l=f({},a[i],r[i]);a[i]=l}return e}),[]).reverse()},T=function(e,t){if(Array.isArray(e)&&e.length)for(var n=0;n<e.length;n+=1)if(e[n][t])return!0;return!1},N=function(e){return Array.isArray(e)?e.join(""):e},L=function(e,t){return Array.isArray(e)?e.reduce((function(e,n){return function(e,t){for(var n=Object.keys(e),a=0;a<n.length;a+=1)if(t[n[a]]&&t[n[a]].includes(e[n[a]]))return!0;return!1}(n,t)?e.priority.push(n):e.default.push(n),e}),{priority:[],default:[]}):{default:e}},O=function(e,t){var n;return f({},e,((n={})[t]=void 0,n))},P=[h.NOSCRIPT,h.SCRIPT,h.STYLE],R=function(e,t){return void 0===t&&(t=!0),!1===t?String(e):String(e).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")},I=function(e){return Object.keys(e).reduce((function(t,n){var a=void 0!==e[n]?n+'="'+e[n]+'"':""+n;return t?t+" "+a:a}),"")},M=function(e,t){return void 0===t&&(t={}),Object.keys(e).reduce((function(t,n){return t[w[n]||n]=e[n],t}),t)},D=function(e,t){return t.map((function(t,n){var r,o=((r={key:n})["data-rh"]=!0,r);return Object.keys(t).forEach((function(e){var n=w[e]||e;"innerHTML"===n||"cssText"===n?o.dangerouslySetInnerHTML={__html:t.innerHTML||t.cssText}:o[n]=t[e]})),a.createElement(e,o)}))},F=function(e,t,n){switch(e){case h.TITLE:return{toComponent:function(){return n=t.titleAttributes,(r={key:e=t.title})["data-rh"]=!0,o=M(n,r),[a.createElement(h.TITLE,o,e)];var e,n,r,o},toString:function(){return function(e,t,n,a){var r=I(n),o=N(t);return r?"<"+e+' data-rh="true" '+r+">"+R(o,a)+"</"+e+">":"<"+e+' data-rh="true">'+R(o,a)+"</"+e+">"}(e,t.title,t.titleAttributes,n)}};case"bodyAttributes":case"htmlAttributes":return{toComponent:function(){return M(t)},toString:function(){return I(t)}};default:return{toComponent:function(){return D(e,t)},toString:function(){return function(e,t,n){return t.reduce((function(t,a){var r=Object.keys(a).filter((function(e){return!("innerHTML"===e||"cssText"===e)})).reduce((function(e,t){var r=void 0===a[t]?t:t+'="'+R(a[t],n)+'"';return e?e+" "+r:r}),""),o=a.innerHTML||a.cssText||"",s=-1===P.indexOf(e);return t+"<"+e+' data-rh="true" '+r+(s?"/>":">"+o+"</"+e+">")}),"")}(e,t,n)}}}},B=function(e){var t=e.baseTag,n=e.bodyAttributes,a=e.encode,r=e.htmlAttributes,o=e.noscriptTags,s=e.styleTags,i=e.title,l=void 0===i?"":i,c=e.titleAttributes,u=e.linkTags,d=e.metaTags,f=e.scriptTags,p={toComponent:function(){},toString:function(){return""}};if(e.prioritizeSeoTags){var m=function(e){var t=e.linkTags,n=e.scriptTags,a=e.encode,r=L(e.metaTags,v),o=L(t,b),s=L(n,y);return{priorityMethods:{toComponent:function(){return[].concat(D(h.META,r.priority),D(h.LINK,o.priority),D(h.SCRIPT,s.priority))},toString:function(){return F(h.META,r.priority,a)+" "+F(h.LINK,o.priority,a)+" "+F(h.SCRIPT,s.priority,a)}},metaTags:r.default,linkTags:o.default,scriptTags:s.default}}(e);p=m.priorityMethods,u=m.linkTags,d=m.metaTags,f=m.scriptTags}return{priority:p,base:F(h.BASE,t,a),bodyAttributes:F("bodyAttributes",n,a),htmlAttributes:F("htmlAttributes",r,a),link:F(h.LINK,u,a),meta:F(h.META,d,a),noscript:F(h.NOSCRIPT,o,a),script:F(h.SCRIPT,f,a),style:F(h.STYLE,s,a),title:F(h.TITLE,{title:l,titleAttributes:c},a)}},j=[],z=function(e,t){var n=this;void 0===t&&(t="undefined"!=typeof document),this.instances=[],this.value={setHelmet:function(e){n.context.helmet=e},helmetInstances:{get:function(){return n.canUseDOM?j:n.instances},add:function(e){(n.canUseDOM?j:n.instances).push(e)},remove:function(e){var t=(n.canUseDOM?j:n.instances).indexOf(e);(n.canUseDOM?j:n.instances).splice(t,1)}}},this.context=e,this.canUseDOM=t,t||(e.helmet=B({baseTag:[],bodyAttributes:{},encodeSpecialCharacters:!0,htmlAttributes:{},linkTags:[],metaTags:[],noscriptTags:[],scriptTags:[],styleTags:[],title:"",titleAttributes:{}}))},$=a.createContext({}),U=o().shape({setHelmet:o().func,helmetInstances:o().shape({get:o().func,add:o().func,remove:o().func})}),H="undefined"!=typeof document,V=function(e){function t(n){var a;return(a=e.call(this,n)||this).helmetData=new z(a.props.context,t.canUseDOM),a}return p(t,e),t.prototype.render=function(){return a.createElement($.Provider,{value:this.helmetData.value},this.props.children)},t}(a.Component);V.canUseDOM=H,V.propTypes={context:o().shape({helmet:o().shape()}),children:o().node.isRequired},V.defaultProps={context:{}},V.displayName="HelmetProvider";var G=function(e,t){var n,a=document.head||document.querySelector(h.HEAD),r=a.querySelectorAll(e+"[data-rh]"),o=[].slice.call(r),s=[];return t&&t.length&&t.forEach((function(t){var a=document.createElement(e);for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&("innerHTML"===r?a.innerHTML=t.innerHTML:"cssText"===r?a.styleSheet?a.styleSheet.cssText=t.cssText:a.appendChild(document.createTextNode(t.cssText)):a.setAttribute(r,void 0===t[r]?"":t[r]));a.setAttribute("data-rh","true"),o.some((function(e,t){return n=t,a.isEqualNode(e)}))?o.splice(n,1):s.push(a)})),o.forEach((function(e){return e.parentNode.removeChild(e)})),s.forEach((function(e){return a.appendChild(e)})),{oldTags:o,newTags:s}},W=function(e,t){var n=document.getElementsByTagName(e)[0];if(n){for(var a=n.getAttribute("data-rh"),r=a?a.split(","):[],o=[].concat(r),s=Object.keys(t),i=0;i<s.length;i+=1){var l=s[i],c=t[l]||"";n.getAttribute(l)!==c&&n.setAttribute(l,c),-1===r.indexOf(l)&&r.push(l);var u=o.indexOf(l);-1!==u&&o.splice(u,1)}for(var d=o.length-1;d>=0;d-=1)n.removeAttribute(o[d]);r.length===o.length?n.removeAttribute("data-rh"):n.getAttribute("data-rh")!==s.join(",")&&n.setAttribute("data-rh",s.join(","))}},Y=function(e,t){var n=e.baseTag,a=e.htmlAttributes,r=e.linkTags,o=e.metaTags,s=e.noscriptTags,i=e.onChangeClientState,l=e.scriptTags,c=e.styleTags,u=e.title,d=e.titleAttributes;W(h.BODY,e.bodyAttributes),W(h.HTML,a),function(e,t){void 0!==e&&document.title!==e&&(document.title=N(e)),W(h.TITLE,t)}(u,d);var f={baseTag:G(h.BASE,n),linkTags:G(h.LINK,r),metaTags:G(h.META,o),noscriptTags:G(h.NOSCRIPT,s),scriptTags:G(h.SCRIPT,l),styleTags:G(h.STYLE,c)},p={},m={};Object.keys(f).forEach((function(e){var t=f[e],n=t.newTags,a=t.oldTags;n.length&&(p[e]=n),a.length&&(m[e]=f[e].oldTags)})),t&&t(),i(e,p,m)},K=null,Q=function(e){function t(){for(var t,n=arguments.length,a=new Array(n),r=0;r<n;r++)a[r]=arguments[r];return(t=e.call.apply(e,[this].concat(a))||this).rendered=!1,t}p(t,e);var n=t.prototype;return n.shouldComponentUpdate=function(e){return!d()(e,this.props)},n.componentDidUpdate=function(){this.emitChange()},n.componentWillUnmount=function(){this.props.context.helmetInstances.remove(this),this.emitChange()},n.emitChange=function(){var e,t,n=this.props.context,a=n.setHelmet,r=null,o=(e=n.helmetInstances.get().map((function(e){var t=f({},e.props);return delete t.context,t})),{baseTag:C(["href"],e),bodyAttributes:A("bodyAttributes",e),defer:E(e,"defer"),encode:E(e,"encodeSpecialCharacters"),htmlAttributes:A("htmlAttributes",e),linkTags:q(h.LINK,["rel","href"],e),metaTags:q(h.META,["name","charset","http-equiv","property","itemprop"],e),noscriptTags:q(h.NOSCRIPT,["innerHTML"],e),onChangeClientState:_(e),scriptTags:q(h.SCRIPT,["src","innerHTML"],e),styleTags:q(h.STYLE,["cssText"],e),title:k(e),titleAttributes:A("titleAttributes",e),prioritizeSeoTags:T(e,"prioritizeSeoTags")});V.canUseDOM?(t=o,K&&cancelAnimationFrame(K),t.defer?K=requestAnimationFrame((function(){Y(t,(function(){K=null}))})):(Y(t),K=null)):B&&(r=B(o)),a(r)},n.init=function(){this.rendered||(this.rendered=!0,this.props.context.helmetInstances.add(this),this.emitChange())},n.render=function(){return this.init(),null},t}(a.Component);Q.propTypes={context:U.isRequired},Q.displayName="HelmetDispatcher";var X=["children"],Z=["children"],J=function(e){function t(){return e.apply(this,arguments)||this}p(t,e);var n=t.prototype;return n.shouldComponentUpdate=function(e){return!i()(O(this.props,"helmetData"),O(e,"helmetData"))},n.mapNestedChildrenToProps=function(e,t){if(!t)return null;switch(e.type){case h.SCRIPT:case h.NOSCRIPT:return{innerHTML:t};case h.STYLE:return{cssText:t};default:throw new Error("<"+e.type+" /> elements are self-closing and can not contain children. Refer to our API for more information.")}},n.flattenArrayTypeChildren=function(e){var t,n=e.child,a=e.arrayTypeChildren;return f({},a,((t={})[n.type]=[].concat(a[n.type]||[],[f({},e.newChildProps,this.mapNestedChildrenToProps(n,e.nestedChildren))]),t))},n.mapObjectTypeChildren=function(e){var t,n,a=e.child,r=e.newProps,o=e.newChildProps,s=e.nestedChildren;switch(a.type){case h.TITLE:return f({},r,((t={})[a.type]=s,t.titleAttributes=f({},o),t));case h.BODY:return f({},r,{bodyAttributes:f({},o)});case h.HTML:return f({},r,{htmlAttributes:f({},o)});default:return f({},r,((n={})[a.type]=f({},o),n))}},n.mapArrayTypeChildrenToProps=function(e,t){var n=f({},t);return Object.keys(e).forEach((function(t){var a;n=f({},n,((a={})[t]=e[t],a))})),n},n.warnOnInvalidChildren=function(e,t){return c()(x.some((function(t){return e.type===t})),"function"==typeof e.type?"You may be attempting to nest <Helmet> components within each other, which is not allowed. Refer to our API for more information.":"Only elements types "+x.join(", ")+" are allowed. Helmet does not support rendering <"+e.type+"> elements. Refer to our API for more information."),c()(!t||"string"==typeof t||Array.isArray(t)&&!t.some((function(e){return"string"!=typeof e})),"Helmet expects a string as a child of <"+e.type+">. Did you forget to wrap your children in braces? ( <"+e.type+">{``}</"+e.type+"> ) Refer to our API for more information."),!0},n.mapChildrenToProps=function(e,t){var n=this,r={};return a.Children.forEach(e,(function(e){if(e&&e.props){var a=e.props,o=a.children,s=g(a,X),i=Object.keys(s).reduce((function(e,t){return e[S[t]||t]=s[t],e}),{}),l=e.type;switch("symbol"==typeof l?l=l.toString():n.warnOnInvalidChildren(e,o),l){case h.FRAGMENT:t=n.mapChildrenToProps(o,t);break;case h.LINK:case h.META:case h.NOSCRIPT:case h.SCRIPT:case h.STYLE:r=n.flattenArrayTypeChildren({child:e,arrayTypeChildren:r,newChildProps:i,nestedChildren:o});break;default:t=n.mapObjectTypeChildren({child:e,newProps:t,newChildProps:i,nestedChildren:o})}}})),this.mapArrayTypeChildrenToProps(r,t)},n.render=function(){var e=this.props,t=e.children,n=g(e,Z),r=f({},n),o=n.helmetData;return t&&(r=this.mapChildrenToProps(t,r)),!o||o instanceof z||(o=new z(o.context,o.instances)),o?a.createElement(Q,f({},r,{context:o.value,helmetData:void 0})):a.createElement($.Consumer,null,(function(e){return a.createElement(Q,f({},r,{context:e}))}))},t}(a.Component);J.propTypes={base:o().object,bodyAttributes:o().object,children:o().oneOfType([o().arrayOf(o().node),o().node]),defaultTitle:o().string,defer:o().bool,encodeSpecialCharacters:o().bool,htmlAttributes:o().object,link:o().arrayOf(o().object),meta:o().arrayOf(o().object),noscript:o().arrayOf(o().object),onChangeClientState:o().func,script:o().arrayOf(o().object),style:o().arrayOf(o().object),title:o().string,titleAttributes:o().object,titleTemplate:o().string,prioritizeSeoTags:o().bool,helmetData:o().object},J.defaultProps={defer:!0,encodeSpecialCharacters:!0,prioritizeSeoTags:!1},J.displayName="Helmet"},2799:(e,t)=>{"use strict";var n="function"==typeof Symbol&&Symbol.for,a=n?Symbol.for("react.element"):60103,r=n?Symbol.for("react.portal"):60106,o=n?Symbol.for("react.fragment"):60107,s=n?Symbol.for("react.strict_mode"):60108,i=n?Symbol.for("react.profiler"):60114,l=n?Symbol.for("react.provider"):60109,c=n?Symbol.for("react.context"):60110,u=n?Symbol.for("react.async_mode"):60111,d=n?Symbol.for("react.concurrent_mode"):60111,f=n?Symbol.for("react.forward_ref"):60112,p=n?Symbol.for("react.suspense"):60113,m=n?Symbol.for("react.suspense_list"):60120,g=n?Symbol.for("react.memo"):60115,h=n?Symbol.for("react.lazy"):60116,b=n?Symbol.for("react.block"):60121,y=n?Symbol.for("react.fundamental"):60117,v=n?Symbol.for("react.responder"):60118,x=n?Symbol.for("react.scope"):60119;function w(e){if("object"==typeof e&&null!==e){var t=e.$$typeof;switch(t){case a:switch(e=e.type){case u:case d:case o:case i:case s:case p:return e;default:switch(e=e&&e.$$typeof){case c:case f:case h:case g:case l:return e;default:return t}}case r:return t}}}function S(e){return w(e)===d}t.AsyncMode=u,t.ConcurrentMode=d,t.ContextConsumer=c,t.ContextProvider=l,t.Element=a,t.ForwardRef=f,t.Fragment=o,t.Lazy=h,t.Memo=g,t.Portal=r,t.Profiler=i,t.StrictMode=s,t.Suspense=p,t.isAsyncMode=function(e){return S(e)||w(e)===u},t.isConcurrentMode=S,t.isContextConsumer=function(e){return w(e)===c},t.isContextProvider=function(e){return w(e)===l},t.isElement=function(e){return"object"==typeof e&&null!==e&&e.$$typeof===a},t.isForwardRef=function(e){return w(e)===f},t.isFragment=function(e){return w(e)===o},t.isLazy=function(e){return w(e)===h},t.isMemo=function(e){return w(e)===g},t.isPortal=function(e){return w(e)===r},t.isProfiler=function(e){return w(e)===i},t.isStrictMode=function(e){return w(e)===s},t.isSuspense=function(e){return w(e)===p},t.isValidElementType=function(e){return"string"==typeof e||"function"==typeof e||e===o||e===d||e===i||e===s||e===p||e===m||"object"==typeof e&&null!==e&&(e.$$typeof===h||e.$$typeof===g||e.$$typeof===l||e.$$typeof===c||e.$$typeof===f||e.$$typeof===y||e.$$typeof===v||e.$$typeof===x||e.$$typeof===b)},t.typeOf=w},4363:(e,t,n)=>{"use strict";e.exports=n(2799)},3259:(e,t,n)=>{"use strict";function a(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,e.__proto__=t}function r(e){if(void 0===e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return e}function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function s(){return s=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var a in n)Object.prototype.hasOwnProperty.call(n,a)&&(e[a]=n[a])}return e},s.apply(this,arguments)}var i=n(6540),l=n(5556),c=[],u=[];function d(e){var t=e(),n={loading:!0,loaded:null,error:null};return n.promise=t.then((function(e){return n.loading=!1,n.loaded=e,e})).catch((function(e){throw n.loading=!1,n.error=e,e})),n}function f(e){var t={loading:!1,loaded:{},error:null},n=[];try{Object.keys(e).forEach((function(a){var r=d(e[a]);r.loading?t.loading=!0:(t.loaded[a]=r.loaded,t.error=r.error),n.push(r.promise),r.promise.then((function(e){t.loaded[a]=e})).catch((function(e){t.error=e}))}))}catch(a){t.error=a}return t.promise=Promise.all(n).then((function(e){return t.loading=!1,e})).catch((function(e){throw t.loading=!1,e})),t}function p(e,t){return i.createElement((n=e)&&n.__esModule?n.default:n,t);var n}function m(e,t){var d,f;if(!t.loading)throw new Error("react-loadable requires a `loading` component");var m=s({loader:null,loading:null,delay:200,timeout:null,render:p,webpack:null,modules:null},t),g=null;function h(){return g||(g=e(m.loader)),g.promise}return c.push(h),"function"==typeof m.webpack&&u.push((function(){if((0,m.webpack)().every((function(e){return void 0!==e&&void 0!==n.m[e]})))return h()})),f=d=function(t){function n(n){var a;return o(r(r(a=t.call(this,n)||this)),"retry",(function(){a.setState({error:null,loading:!0,timedOut:!1}),g=e(m.loader),a._loadModule()})),h(),a.state={error:g.error,pastDelay:!1,timedOut:!1,loading:g.loading,loaded:g.loaded},a}a(n,t),n.preload=function(){return h()};var s=n.prototype;return s.UNSAFE_componentWillMount=function(){this._loadModule()},s.componentDidMount=function(){this._mounted=!0},s._loadModule=function(){var e=this;if(this.context.loadable&&Array.isArray(m.modules)&&m.modules.forEach((function(t){e.context.loadable.report(t)})),g.loading){var t=function(t){e._mounted&&e.setState(t)};"number"==typeof m.delay&&(0===m.delay?this.setState({pastDelay:!0}):this._delay=setTimeout((function(){t({pastDelay:!0})}),m.delay)),"number"==typeof m.timeout&&(this._timeout=setTimeout((function(){t({timedOut:!0})}),m.timeout));var n=function(){t({error:g.error,loaded:g.loaded,loading:g.loading}),e._clearTimeouts()};g.promise.then((function(){return n(),null})).catch((function(e){return n(),null}))}},s.componentWillUnmount=function(){this._mounted=!1,this._clearTimeouts()},s._clearTimeouts=function(){clearTimeout(this._delay),clearTimeout(this._timeout)},s.render=function(){return this.state.loading||this.state.error?i.createElement(m.loading,{isLoading:this.state.loading,pastDelay:this.state.pastDelay,timedOut:this.state.timedOut,error:this.state.error,retry:this.retry}):this.state.loaded?m.render(this.state.loaded,this.props):null},n}(i.Component),o(d,"contextTypes",{loadable:l.shape({report:l.func.isRequired})}),f}function g(e){return m(d,e)}g.Map=function(e){if("function"!=typeof e.render)throw new Error("LoadableMap requires a `render(loaded, props)` function");return m(f,e)};var h=function(e){function t(){return e.apply(this,arguments)||this}a(t,e);var n=t.prototype;return n.getChildContext=function(){return{loadable:{report:this.props.report}}},n.render=function(){return i.Children.only(this.props.children)},t}(i.Component);function b(e){for(var t=[];e.length;){var n=e.pop();t.push(n())}return Promise.all(t).then((function(){if(e.length)return b(e)}))}o(h,"propTypes",{report:l.func.isRequired}),o(h,"childContextTypes",{loadable:l.shape({report:l.func.isRequired}).isRequired}),g.Capture=h,g.preloadAll=function(){return new Promise((function(e,t){b(c).then(e,t)}))},g.preloadReady=function(){return new Promise((function(e,t){b(u).then(e,e)}))},e.exports=g},2831:(e,t,n)=>{"use strict";n.d(t,{u:()=>s,v:()=>i});var a=n(6347),r=n(8168),o=n(6540);function s(e,t,n){return void 0===n&&(n=[]),e.some((function(e){var r=e.path?(0,a.B6)(t,e):n.length?n[n.length-1].match:a.Ix.computeRootMatch(t);return r&&(n.push({route:e,match:r}),e.routes&&s(e.routes,t,n)),r})),n}function i(e,t,n){return void 0===t&&(t={}),void 0===n&&(n={}),e?o.createElement(a.dO,n,e.map((function(e,n){return o.createElement(a.qh,{key:e.key||n,path:e.path,exact:e.exact,strict:e.strict,render:function(n){return e.render?e.render((0,r.A)({},n,{},t,{route:e})):o.createElement(e.component,(0,r.A)({},n,t,{route:e}))}})}))):null}},4625:(e,t,n)=>{"use strict";n.d(t,{Kd:()=>u,N_:()=>h,k2:()=>v});var a=n(6347),r=n(2892),o=n(6540),s=n(1513),i=n(8168),l=n(8587),c=n(1561),u=function(e){function t(){for(var t,n=arguments.length,a=new Array(n),r=0;r<n;r++)a[r]=arguments[r];return(t=e.call.apply(e,[this].concat(a))||this).history=(0,s.zR)(t.props),t}return(0,r.A)(t,e),t.prototype.render=function(){return o.createElement(a.Ix,{history:this.history,children:this.props.children})},t}(o.Component);o.Component;var d=function(e,t){return"function"==typeof e?e(t):e},f=function(e,t){return"string"==typeof e?(0,s.yJ)(e,null,null,t):e},p=function(e){return e},m=o.forwardRef;void 0===m&&(m=p);var g=m((function(e,t){var n=e.innerRef,a=e.navigate,r=e.onClick,s=(0,l.A)(e,["innerRef","navigate","onClick"]),c=s.target,u=(0,i.A)({},s,{onClick:function(e){try{r&&r(e)}catch(t){throw e.preventDefault(),t}e.defaultPrevented||0!==e.button||c&&"_self"!==c||function(e){return!!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)}(e)||(e.preventDefault(),a())}});return u.ref=p!==m&&t||n,o.createElement("a",u)}));var h=m((function(e,t){var n=e.component,r=void 0===n?g:n,u=e.replace,h=e.to,b=e.innerRef,y=(0,l.A)(e,["component","replace","to","innerRef"]);return o.createElement(a.XZ.Consumer,null,(function(e){e||(0,c.A)(!1);var n=e.history,a=f(d(h,e.location),e.location),l=a?n.createHref(a):"",g=(0,i.A)({},y,{href:l,navigate:function(){var t=d(h,e.location),a=(0,s.AO)(e.location)===(0,s.AO)(f(t));(u||a?n.replace:n.push)(t)}});return p!==m?g.ref=t||b:g.innerRef=b,o.createElement(r,g)}))})),b=function(e){return e},y=o.forwardRef;void 0===y&&(y=b);var v=y((function(e,t){var n=e["aria-current"],r=void 0===n?"page":n,s=e.activeClassName,u=void 0===s?"active":s,p=e.activeStyle,m=e.className,g=e.exact,v=e.isActive,x=e.location,w=e.sensitive,S=e.strict,E=e.style,k=e.to,_=e.innerRef,A=(0,l.A)(e,["aria-current","activeClassName","activeStyle","className","exact","isActive","location","sensitive","strict","style","to","innerRef"]);return o.createElement(a.XZ.Consumer,null,(function(e){e||(0,c.A)(!1);var n=x||e.location,s=f(d(k,n),n),l=s.pathname,C=l&&l.replace(/([.+*?=^!:${}()[\]|/\\])/g,"\\$1"),q=C?(0,a.B6)(n.pathname,{path:C,exact:g,sensitive:w,strict:S}):null,T=!!(v?v(q,n):q),N="function"==typeof m?m(T):m,L="function"==typeof E?E(T):E;T&&(N=function(){for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];return t.filter((function(e){return e})).join(" ")}(N,u),L=(0,i.A)({},L,p));var O=(0,i.A)({"aria-current":T&&r||null,className:N,style:L,to:s},A);return b!==y?O.ref=t||_:O.innerRef=_,o.createElement(h,O)}))}))},6347:(e,t,n)=>{"use strict";n.d(t,{B6:()=>E,Ix:()=>v,W6:()=>O,XZ:()=>y,dO:()=>N,qh:()=>k,zy:()=>P});var a=n(2892),r=n(6540),o=n(5556),s=n.n(o),i=n(1513),l=n(1561),c=n(8168),u=n(8505),d=n.n(u),f=(n(4363),n(8587)),p=(n(4146),1073741823),m="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:void 0!==n.g?n.g:{};var g=r.createContext||function(e,t){var n,o,i="__create-react-context-"+function(){var e="__global_unique_id__";return m[e]=(m[e]||0)+1}()+"__",l=function(e){function n(){for(var t,n,a,r=arguments.length,o=new Array(r),s=0;s<r;s++)o[s]=arguments[s];return(t=e.call.apply(e,[this].concat(o))||this).emitter=(n=t.props.value,a=[],{on:function(e){a.push(e)},off:function(e){a=a.filter((function(t){return t!==e}))},get:function(){return n},set:function(e,t){n=e,a.forEach((function(e){return e(n,t)}))}}),t}(0,a.A)(n,e);var r=n.prototype;return r.getChildContext=function(){var e;return(e={})[i]=this.emitter,e},r.componentWillReceiveProps=function(e){if(this.props.value!==e.value){var n,a=this.props.value,r=e.value;((o=a)===(s=r)?0!==o||1/o==1/s:o!=o&&s!=s)?n=0:(n="function"==typeof t?t(a,r):p,0!==(n|=0)&&this.emitter.set(e.value,n))}var o,s},r.render=function(){return this.props.children},n}(r.Component);l.childContextTypes=((n={})[i]=s().object.isRequired,n);var c=function(t){function n(){for(var e,n=arguments.length,a=new Array(n),r=0;r<n;r++)a[r]=arguments[r];return(e=t.call.apply(t,[this].concat(a))||this).observedBits=void 0,e.state={value:e.getValue()},e.onUpdate=function(t,n){(0|e.observedBits)&n&&e.setState({value:e.getValue()})},e}(0,a.A)(n,t);var r=n.prototype;return r.componentWillReceiveProps=function(e){var t=e.observedBits;this.observedBits=null==t?p:t},r.componentDidMount=function(){this.context[i]&&this.context[i].on(this.onUpdate);var e=this.props.observedBits;this.observedBits=null==e?p:e},r.componentWillUnmount=function(){this.context[i]&&this.context[i].off(this.onUpdate)},r.getValue=function(){return this.context[i]?this.context[i].get():e},r.render=function(){return(e=this.props.children,Array.isArray(e)?e[0]:e)(this.state.value);var e},n}(r.Component);return c.contextTypes=((o={})[i]=s().object,o),{Provider:l,Consumer:c}},h=function(e){var t=g();return t.displayName=e,t},b=h("Router-History"),y=h("Router"),v=function(e){function t(t){var n;return(n=e.call(this,t)||this).state={location:t.history.location},n._isMounted=!1,n._pendingLocation=null,t.staticContext||(n.unlisten=t.history.listen((function(e){n._pendingLocation=e}))),n}(0,a.A)(t,e),t.computeRootMatch=function(e){return{path:"/",url:"/",params:{},isExact:"/"===e}};var n=t.prototype;return n.componentDidMount=function(){var e=this;this._isMounted=!0,this.unlisten&&this.unlisten(),this.props.staticContext||(this.unlisten=this.props.history.listen((function(t){e._isMounted&&e.setState({location:t})}))),this._pendingLocation&&this.setState({location:this._pendingLocation})},n.componentWillUnmount=function(){this.unlisten&&(this.unlisten(),this._isMounted=!1,this._pendingLocation=null)},n.render=function(){return r.createElement(y.Provider,{value:{history:this.props.history,location:this.state.location,match:t.computeRootMatch(this.state.location.pathname),staticContext:this.props.staticContext}},r.createElement(b.Provider,{children:this.props.children||null,value:this.props.history}))},t}(r.Component);r.Component;r.Component;var x={},w=1e4,S=0;function E(e,t){void 0===t&&(t={}),("string"==typeof t||Array.isArray(t))&&(t={path:t});var n=t,a=n.path,r=n.exact,o=void 0!==r&&r,s=n.strict,i=void 0!==s&&s,l=n.sensitive,c=void 0!==l&&l;return[].concat(a).reduce((function(t,n){if(!n&&""!==n)return null;if(t)return t;var a=function(e,t){var n=""+t.end+t.strict+t.sensitive,a=x[n]||(x[n]={});if(a[e])return a[e];var r=[],o={regexp:d()(e,r,t),keys:r};return S<w&&(a[e]=o,S++),o}(n,{end:o,strict:i,sensitive:c}),r=a.regexp,s=a.keys,l=r.exec(e);if(!l)return null;var u=l[0],f=l.slice(1),p=e===u;return o&&!p?null:{path:n,url:"/"===n&&""===u?"/":u,isExact:p,params:s.reduce((function(e,t,n){return e[t.name]=f[n],e}),{})}}),null)}var k=function(e){function t(){return e.apply(this,arguments)||this}return(0,a.A)(t,e),t.prototype.render=function(){var e=this;return r.createElement(y.Consumer,null,(function(t){t||(0,l.A)(!1);var n=e.props.location||t.location,a=e.props.computedMatch?e.props.computedMatch:e.props.path?E(n.pathname,e.props):t.match,o=(0,c.A)({},t,{location:n,match:a}),s=e.props,i=s.children,u=s.component,d=s.render;return Array.isArray(i)&&function(e){return 0===r.Children.count(e)}(i)&&(i=null),r.createElement(y.Provider,{value:o},o.match?i?"function"==typeof i?i(o):i:u?r.createElement(u,o):d?d(o):null:"function"==typeof i?i(o):null)}))},t}(r.Component);function _(e){return"/"===e.charAt(0)?e:"/"+e}function A(e,t){if(!e)return t;var n=_(e);return 0!==t.pathname.indexOf(n)?t:(0,c.A)({},t,{pathname:t.pathname.substr(n.length)})}function C(e){return"string"==typeof e?e:(0,i.AO)(e)}function q(e){return function(){(0,l.A)(!1)}}function T(){}r.Component;var N=function(e){function t(){return e.apply(this,arguments)||this}return(0,a.A)(t,e),t.prototype.render=function(){var e=this;return r.createElement(y.Consumer,null,(function(t){t||(0,l.A)(!1);var n,a,o=e.props.location||t.location;return r.Children.forEach(e.props.children,(function(e){if(null==a&&r.isValidElement(e)){n=e;var s=e.props.path||e.props.from;a=s?E(o.pathname,(0,c.A)({},e.props,{path:s})):t.match}})),a?r.cloneElement(n,{location:o,computedMatch:a}):null}))},t}(r.Component);var L=r.useContext;function O(){return L(b)}function P(){return L(y).location}},8505:(e,t,n)=>{var a=n(4634);e.exports=p,e.exports.parse=o,e.exports.compile=function(e,t){return i(o(e,t),t)},e.exports.tokensToFunction=i,e.exports.tokensToRegExp=f;var r=new RegExp(["(\\\\.)","([\\/.])?(?:(?:\\:(\\w+)(?:\\(((?:\\\\.|[^\\\\()])+)\\))?|\\(((?:\\\\.|[^\\\\()])+)\\))([+*?])?|(\\*))"].join("|"),"g");function o(e,t){for(var n,a=[],o=0,s=0,i="",u=t&&t.delimiter||"/";null!=(n=r.exec(e));){var d=n[0],f=n[1],p=n.index;if(i+=e.slice(s,p),s=p+d.length,f)i+=f[1];else{var m=e[s],g=n[2],h=n[3],b=n[4],y=n[5],v=n[6],x=n[7];i&&(a.push(i),i="");var w=null!=g&&null!=m&&m!==g,S="+"===v||"*"===v,E="?"===v||"*"===v,k=n[2]||u,_=b||y;a.push({name:h||o++,prefix:g||"",delimiter:k,optional:E,repeat:S,partial:w,asterisk:!!x,pattern:_?c(_):x?".*":"[^"+l(k)+"]+?"})}}return s<e.length&&(i+=e.substr(s)),i&&a.push(i),a}function s(e){return encodeURI(e).replace(/[\/?#]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}function i(e,t){for(var n=new Array(e.length),r=0;r<e.length;r++)"object"==typeof e[r]&&(n[r]=new RegExp("^(?:"+e[r].pattern+")$",d(t)));return function(t,r){for(var o="",i=t||{},l=(r||{}).pretty?s:encodeURIComponent,c=0;c<e.length;c++){var u=e[c];if("string"!=typeof u){var d,f=i[u.name];if(null==f){if(u.optional){u.partial&&(o+=u.prefix);continue}throw new TypeError('Expected "'+u.name+'" to be defined')}if(a(f)){if(!u.repeat)throw new TypeError('Expected "'+u.name+'" to not repeat, but received `'+JSON.stringify(f)+"`");if(0===f.length){if(u.optional)continue;throw new TypeError('Expected "'+u.name+'" to not be empty')}for(var p=0;p<f.length;p++){if(d=l(f[p]),!n[c].test(d))throw new TypeError('Expected all "'+u.name+'" to match "'+u.pattern+'", but received `'+JSON.stringify(d)+"`");o+=(0===p?u.prefix:u.delimiter)+d}}else{if(d=u.asterisk?encodeURI(f).replace(/[?#]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()})):l(f),!n[c].test(d))throw new TypeError('Expected "'+u.name+'" to match "'+u.pattern+'", but received "'+d+'"');o+=u.prefix+d}}else o+=u}return o}}function l(e){return e.replace(/([.+*?=^!:${}()[\]|\/\\])/g,"\\$1")}function c(e){return e.replace(/([=!:$\/()])/g,"\\$1")}function u(e,t){return e.keys=t,e}function d(e){return e&&e.sensitive?"":"i"}function f(e,t,n){a(t)||(n=t||n,t=[]);for(var r=(n=n||{}).strict,o=!1!==n.end,s="",i=0;i<e.length;i++){var c=e[i];if("string"==typeof c)s+=l(c);else{var f=l(c.prefix),p="(?:"+c.pattern+")";t.push(c),c.repeat&&(p+="(?:"+f+p+")*"),s+=p=c.optional?c.partial?f+"("+p+")?":"(?:"+f+"("+p+"))?":f+"("+p+")"}}var m=l(n.delimiter||"/"),g=s.slice(-m.length)===m;return r||(s=(g?s.slice(0,-m.length):s)+"(?:"+m+"(?=$))?"),s+=o?"$":r&&g?"":"(?="+m+"|$)",u(new RegExp("^"+s,d(n)),t)}function p(e,t,n){return a(t)||(n=t||n,t=[]),n=n||{},e instanceof RegExp?function(e,t){var n=e.source.match(/\((?!\?)/g);if(n)for(var a=0;a<n.length;a++)t.push({name:a,prefix:null,delimiter:null,optional:!1,repeat:!1,partial:!1,asterisk:!1,pattern:null});return u(e,t)}(e,t):a(e)?function(e,t,n){for(var a=[],r=0;r<e.length;r++)a.push(p(e[r],t,n).source);return u(new RegExp("(?:"+a.join("|")+")",d(n)),t)}(e,t,n):function(e,t,n){return f(o(e,n),t,n)}(e,t,n)}},5287:(e,t,n)=>{"use strict";var a=n(5228),r=60103,o=60106;t.Fragment=60107,t.StrictMode=60108,t.Profiler=60114;var s=60109,i=60110,l=60112;t.Suspense=60113;var c=60115,u=60116;if("function"==typeof Symbol&&Symbol.for){var d=Symbol.for;r=d("react.element"),o=d("react.portal"),t.Fragment=d("react.fragment"),t.StrictMode=d("react.strict_mode"),t.Profiler=d("react.profiler"),s=d("react.provider"),i=d("react.context"),l=d("react.forward_ref"),t.Suspense=d("react.suspense"),c=d("react.memo"),u=d("react.lazy")}var f="function"==typeof Symbol&&Symbol.iterator;function p(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n<arguments.length;n++)t+="&args[]="+encodeURIComponent(arguments[n]);return"Minified React error #"+e+"; visit "+t+" for the full message or use the non-minified dev environment for full errors and additional helpful warnings."}var m={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},g={};function h(e,t,n){this.props=e,this.context=t,this.refs=g,this.updater=n||m}function b(){}function y(e,t,n){this.props=e,this.context=t,this.refs=g,this.updater=n||m}h.prototype.isReactComponent={},h.prototype.setState=function(e,t){if("object"!=typeof e&&"function"!=typeof e&&null!=e)throw Error(p(85));this.updater.enqueueSetState(this,e,t,"setState")},h.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")},b.prototype=h.prototype;var v=y.prototype=new b;v.constructor=y,a(v,h.prototype),v.isPureReactComponent=!0;var x={current:null},w=Object.prototype.hasOwnProperty,S={key:!0,ref:!0,__self:!0,__source:!0};function E(e,t,n){var a,o={},s=null,i=null;if(null!=t)for(a in void 0!==t.ref&&(i=t.ref),void 0!==t.key&&(s=""+t.key),t)w.call(t,a)&&!S.hasOwnProperty(a)&&(o[a]=t[a]);var l=arguments.length-2;if(1===l)o.children=n;else if(1<l){for(var c=Array(l),u=0;u<l;u++)c[u]=arguments[u+2];o.children=c}if(e&&e.defaultProps)for(a in l=e.defaultProps)void 0===o[a]&&(o[a]=l[a]);return{$$typeof:r,type:e,key:s,ref:i,props:o,_owner:x.current}}function k(e){return"object"==typeof e&&null!==e&&e.$$typeof===r}var _=/\/+/g;function A(e,t){return"object"==typeof e&&null!==e&&null!=e.key?function(e){var t={"=":"=0",":":"=2"};return"$"+e.replace(/[=:]/g,(function(e){return t[e]}))}(""+e.key):t.toString(36)}function C(e,t,n,a,s){var i=typeof e;"undefined"!==i&&"boolean"!==i||(e=null);var l=!1;if(null===e)l=!0;else switch(i){case"string":case"number":l=!0;break;case"object":switch(e.$$typeof){case r:case o:l=!0}}if(l)return s=s(l=e),e=""===a?"."+A(l,0):a,Array.isArray(s)?(n="",null!=e&&(n=e.replace(_,"$&/")+"/"),C(s,t,n,"",(function(e){return e}))):null!=s&&(k(s)&&(s=function(e,t){return{$$typeof:r,type:e.type,key:t,ref:e.ref,props:e.props,_owner:e._owner}}(s,n+(!s.key||l&&l.key===s.key?"":(""+s.key).replace(_,"$&/")+"/")+e)),t.push(s)),1;if(l=0,a=""===a?".":a+":",Array.isArray(e))for(var c=0;c<e.length;c++){var u=a+A(i=e[c],c);l+=C(i,t,n,u,s)}else if(u=function(e){return null===e||"object"!=typeof e?null:"function"==typeof(e=f&&e[f]||e["@@iterator"])?e:null}(e),"function"==typeof u)for(e=u.call(e),c=0;!(i=e.next()).done;)l+=C(i=i.value,t,n,u=a+A(i,c++),s);else if("object"===i)throw t=""+e,Error(p(31,"[object Object]"===t?"object with keys {"+Object.keys(e).join(", ")+"}":t));return l}function q(e,t,n){if(null==e)return e;var a=[],r=0;return C(e,a,"","",(function(e){return t.call(n,e,r++)})),a}function T(e){if(-1===e._status){var t=e._result;t=t(),e._status=0,e._result=t,t.then((function(t){0===e._status&&(t=t.default,e._status=1,e._result=t)}),(function(t){0===e._status&&(e._status=2,e._result=t)}))}if(1===e._status)return e._result;throw e._result}var N={current:null};function L(){var e=N.current;if(null===e)throw Error(p(321));return e}var O={ReactCurrentDispatcher:N,ReactCurrentBatchConfig:{transition:0},ReactCurrentOwner:x,IsSomeRendererActing:{current:!1},assign:a};t.Children={map:q,forEach:function(e,t,n){q(e,(function(){t.apply(this,arguments)}),n)},count:function(e){var t=0;return q(e,(function(){t++})),t},toArray:function(e){return q(e,(function(e){return e}))||[]},only:function(e){if(!k(e))throw Error(p(143));return e}},t.Component=h,t.PureComponent=y,t.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=O,t.cloneElement=function(e,t,n){if(null==e)throw Error(p(267,e));var o=a({},e.props),s=e.key,i=e.ref,l=e._owner;if(null!=t){if(void 0!==t.ref&&(i=t.ref,l=x.current),void 0!==t.key&&(s=""+t.key),e.type&&e.type.defaultProps)var c=e.type.defaultProps;for(u in t)w.call(t,u)&&!S.hasOwnProperty(u)&&(o[u]=void 0===t[u]&&void 0!==c?c[u]:t[u])}var u=arguments.length-2;if(1===u)o.children=n;else if(1<u){c=Array(u);for(var d=0;d<u;d++)c[d]=arguments[d+2];o.children=c}return{$$typeof:r,type:e.type,key:s,ref:i,props:o,_owner:l}},t.createContext=function(e,t){return void 0===t&&(t=null),(e={$$typeof:i,_calculateChangedBits:t,_currentValue:e,_currentValue2:e,_threadCount:0,Provider:null,Consumer:null}).Provider={$$typeof:s,_context:e},e.Consumer=e},t.createElement=E,t.createFactory=function(e){var t=E.bind(null,e);return t.type=e,t},t.createRef=function(){return{current:null}},t.forwardRef=function(e){return{$$typeof:l,render:e}},t.isValidElement=k,t.lazy=function(e){return{$$typeof:u,_payload:{_status:-1,_result:e},_init:T}},t.memo=function(e,t){return{$$typeof:c,type:e,compare:void 0===t?null:t}},t.useCallback=function(e,t){return L().useCallback(e,t)},t.useContext=function(e,t){return L().useContext(e,t)},t.useDebugValue=function(){},t.useEffect=function(e,t){return L().useEffect(e,t)},t.useImperativeHandle=function(e,t,n){return L().useImperativeHandle(e,t,n)},t.useLayoutEffect=function(e,t){return L().useLayoutEffect(e,t)},t.useMemo=function(e,t){return L().useMemo(e,t)},t.useReducer=function(e,t,n){return L().useReducer(e,t,n)},t.useRef=function(e){return L().useRef(e)},t.useState=function(e){return L().useState(e)},t.version="17.0.2"},6540:(e,t,n)=>{"use strict";e.exports=n(5287)},7463:(e,t)=>{"use strict";var n,a,r,o;if("object"==typeof performance&&"function"==typeof performance.now){var s=performance;t.unstable_now=function(){return s.now()}}else{var i=Date,l=i.now();t.unstable_now=function(){return i.now()-l}}if("undefined"==typeof window||"function"!=typeof MessageChannel){var c=null,u=null,d=function(){if(null!==c)try{var e=t.unstable_now();c(!0,e),c=null}catch(n){throw setTimeout(d,0),n}};n=function(e){null!==c?setTimeout(n,0,e):(c=e,setTimeout(d,0))},a=function(e,t){u=setTimeout(e,t)},r=function(){clearTimeout(u)},t.unstable_shouldYield=function(){return!1},o=t.unstable_forceFrameRate=function(){}}else{var f=window.setTimeout,p=window.clearTimeout;if("undefined"!=typeof console){var m=window.cancelAnimationFrame;"function"!=typeof window.requestAnimationFrame&&console.error("This browser doesn't support requestAnimationFrame. Make sure that you load a polyfill in older browsers. https://reactjs.org/link/react-polyfills"),"function"!=typeof m&&console.error("This browser doesn't support cancelAnimationFrame. Make sure that you load a polyfill in older browsers. https://reactjs.org/link/react-polyfills")}var g=!1,h=null,b=-1,y=5,v=0;t.unstable_shouldYield=function(){return t.unstable_now()>=v},o=function(){},t.unstable_forceFrameRate=function(e){0>e||125<e?console.error("forceFrameRate takes a positive int between 0 and 125, forcing frame rates higher than 125 fps is not supported"):y=0<e?Math.floor(1e3/e):5};var x=new MessageChannel,w=x.port2;x.port1.onmessage=function(){if(null!==h){var e=t.unstable_now();v=e+y;try{h(!0,e)?w.postMessage(null):(g=!1,h=null)}catch(n){throw w.postMessage(null),n}}else g=!1},n=function(e){h=e,g||(g=!0,w.postMessage(null))},a=function(e,n){b=f((function(){e(t.unstable_now())}),n)},r=function(){p(b),b=-1}}function S(e,t){var n=e.length;e.push(t);e:for(;;){var a=n-1>>>1,r=e[a];if(!(void 0!==r&&0<_(r,t)))break e;e[a]=t,e[n]=r,n=a}}function E(e){return void 0===(e=e[0])?null:e}function k(e){var t=e[0];if(void 0!==t){var n=e.pop();if(n!==t){e[0]=n;e:for(var a=0,r=e.length;a<r;){var o=2*(a+1)-1,s=e[o],i=o+1,l=e[i];if(void 0!==s&&0>_(s,n))void 0!==l&&0>_(l,s)?(e[a]=l,e[i]=n,a=i):(e[a]=s,e[o]=n,a=o);else{if(!(void 0!==l&&0>_(l,n)))break e;e[a]=l,e[i]=n,a=i}}}return t}return null}function _(e,t){var n=e.sortIndex-t.sortIndex;return 0!==n?n:e.id-t.id}var A=[],C=[],q=1,T=null,N=3,L=!1,O=!1,P=!1;function R(e){for(var t=E(C);null!==t;){if(null===t.callback)k(C);else{if(!(t.startTime<=e))break;k(C),t.sortIndex=t.expirationTime,S(A,t)}t=E(C)}}function I(e){if(P=!1,R(e),!O)if(null!==E(A))O=!0,n(M);else{var t=E(C);null!==t&&a(I,t.startTime-e)}}function M(e,n){O=!1,P&&(P=!1,r()),L=!0;var o=N;try{for(R(n),T=E(A);null!==T&&(!(T.expirationTime>n)||e&&!t.unstable_shouldYield());){var s=T.callback;if("function"==typeof s){T.callback=null,N=T.priorityLevel;var i=s(T.expirationTime<=n);n=t.unstable_now(),"function"==typeof i?T.callback=i:T===E(A)&&k(A),R(n)}else k(A);T=E(A)}if(null!==T)var l=!0;else{var c=E(C);null!==c&&a(I,c.startTime-n),l=!1}return l}finally{T=null,N=o,L=!1}}var D=o;t.unstable_IdlePriority=5,t.unstable_ImmediatePriority=1,t.unstable_LowPriority=4,t.unstable_NormalPriority=3,t.unstable_Profiling=null,t.unstable_UserBlockingPriority=2,t.unstable_cancelCallback=function(e){e.callback=null},t.unstable_continueExecution=function(){O||L||(O=!0,n(M))},t.unstable_getCurrentPriorityLevel=function(){return N},t.unstable_getFirstCallbackNode=function(){return E(A)},t.unstable_next=function(e){switch(N){case 1:case 2:case 3:var t=3;break;default:t=N}var n=N;N=t;try{return e()}finally{N=n}},t.unstable_pauseExecution=function(){},t.unstable_requestPaint=D,t.unstable_runWithPriority=function(e,t){switch(e){case 1:case 2:case 3:case 4:case 5:break;default:e=3}var n=N;N=e;try{return t()}finally{N=n}},t.unstable_scheduleCallback=function(e,o,s){var i=t.unstable_now();switch("object"==typeof s&&null!==s?s="number"==typeof(s=s.delay)&&0<s?i+s:i:s=i,e){case 1:var l=-1;break;case 2:l=250;break;case 5:l=1073741823;break;case 4:l=1e4;break;default:l=5e3}return e={id:q++,callback:o,priorityLevel:e,startTime:s,expirationTime:l=s+l,sortIndex:-1},s>i?(e.sortIndex=s,S(C,e),null===E(A)&&e===E(C)&&(P?r():P=!0,a(I,s-i))):(e.sortIndex=l,S(A,e),O||L||(O=!0,n(M))),e},t.unstable_wrapCallback=function(e){var t=N;return function(){var n=N;N=t;try{return e.apply(this,arguments)}finally{N=n}}}},9982:(e,t,n)=>{"use strict";e.exports=n(7463)},2833:e=>{e.exports=function(e,t,n,a){var r=n?n.call(a,e,t):void 0;if(void 0!==r)return!!r;if(e===t)return!0;if("object"!=typeof e||!e||"object"!=typeof t||!t)return!1;var o=Object.keys(e),s=Object.keys(t);if(o.length!==s.length)return!1;for(var i=Object.prototype.hasOwnProperty.bind(t),l=0;l<o.length;l++){var c=o[l];if(!i(c))return!1;var u=e[c],d=t[c];if(!1===(r=n?n.call(a,u,d,c):void 0)||void 0===r&&u!==d)return!1}return!0}},1063:(e,t,n)=>{"use strict";var a=n(6540);var r="function"==typeof Object.is?Object.is:function(e,t){return e===t&&(0!==e||1/e==1/t)||e!=e&&t!=t},o=a.useState,s=a.useEffect,i=a.useLayoutEffect,l=a.useDebugValue;function c(e){var t=e.getSnapshot;e=e.value;try{var n=t();return!r(e,n)}catch(a){return!0}}var u="undefined"==typeof window||void 0===window.document||void 0===window.document.createElement?function(e,t){return t()}:function(e,t){var n=t(),a=o({inst:{value:n,getSnapshot:t}}),r=a[0].inst,u=a[1];return i((function(){r.value=n,r.getSnapshot=t,c(r)&&u({inst:r})}),[e,n,t]),s((function(){return c(r)&&u({inst:r}),e((function(){c(r)&&u({inst:r})}))}),[e]),l(n),n};void 0!==a.useSyncExternalStore&&a.useSyncExternalStore},9888:(e,t,n)=>{"use strict";n(1063)},4784:(e,t,n)=>{"use strict";n.d(t,{A:()=>a});const a={title:"GlueSQL",tagline:"GlueSQL is quite sticky. It attaches to anywhere",favicon:"img/favicon.ico",url:"https://gluesql.org",baseUrl:"/docs/0.16.0/",onBrokenLinks:"throw",onBrokenMarkdownLinks:"warn",i18n:{defaultLocale:"en",locales:["en"],path:"i18n",localeConfigs:{}},presets:[["classic",{theme:{customCss:"/home/runner/work/gluesql/gluesql/docs/src/css/custom.css"},pages:!1,docs:{sidebarPath:"/home/runner/work/gluesql/gluesql/docs/sidebars.js",routeBasePath:"/"}}]],themeConfig:{colorMode:{disableSwitch:!1,respectPrefersColorScheme:!0,defaultMode:"light"},navbar:{title:"GlueSQL",items:[{to:"getting-started/rust",position:"left",label:"Getting Started",activeBasePath:"getting-started"},{to:"sql-syntax/intro",position:"left",label:"SQL Syntax",activeBasePath:"sql-syntax"},{to:"ast-builder/intro",position:"left",label:"AST Builder",activeBasePath:"ast-builder"},{to:"storages/intro",position:"left",label:"Storages",activeBasePath:"storages"},{href:"https://gluesql.org/blog",label:"Blog",position:"right"},{href:"https://github.com/gluesql/gluesql",label:"GitHub",position:"right"}],hideOnScroll:!1},prism:{theme:{plain:{color:"#393A34",backgroundColor:"#f6f8fa"},styles:[{types:["comment","prolog","doctype","cdata"],style:{color:"#999988",fontStyle:"italic"}},{types:["namespace"],style:{opacity:.7}},{types:["string","attr-value"],style:{color:"#e3116c"}},{types:["punctuation","operator"],style:{color:"#393A34"}},{types:["entity","url","symbol","number","boolean","variable","constant","property","regex","inserted"],style:{color:"#36acaa"}},{types:["atrule","keyword","attr-name","selector"],style:{color:"#00a4db"}},{types:["function","deleted","tag"],style:{color:"#d73a49"}},{types:["function-variable"],style:{color:"#6f42c1"}},{types:["tag","selector","keyword"],style:{color:"#00009f"}}]},darkTheme:{plain:{color:"#F8F8F2",backgroundColor:"#282A36"},styles:[{types:["prolog","constant","builtin"],style:{color:"rgb(189, 147, 249)"}},{types:["inserted","function"],style:{color:"rgb(80, 250, 123)"}},{types:["deleted"],style:{color:"rgb(255, 85, 85)"}},{types:["changed"],style:{color:"rgb(255, 184, 108)"}},{types:["punctuation","symbol"],style:{color:"rgb(248, 248, 242)"}},{types:["string","char","tag","selector"],style:{color:"rgb(255, 121, 198)"}},{types:["keyword","variable"],style:{color:"rgb(189, 147, 249)",fontStyle:"italic"}},{types:["comment"],style:{color:"rgb(98, 114, 164)"}},{types:["attr-name"],style:{color:"rgb(241, 250, 140)"}}]},additionalLanguages:["rust","toml"],magicComments:[{className:"theme-code-block-highlighted-line",line:"highlight-next-line",block:{start:"highlight-start",end:"highlight-end"}}]},docs:{versionPersistence:"localStorage",sidebar:{hideable:!1,autoCollapseCategories:!1}},metadata:[],tableOfContents:{minHeadingLevel:2,maxHeadingLevel:3}},baseUrlIssueBanner:!0,onDuplicateRoutes:"warn",staticDirectories:["static"],customFields:{},plugins:[],themes:[],scripts:[],headTags:[],stylesheets:[],clientModules:[],titleDelimiter:"|",noIndex:!1,markdown:{mermaid:!1}}},8168:(e,t,n)=>{"use strict";function a(){return a=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var a in n)({}).hasOwnProperty.call(n,a)&&(e[a]=n[a])}return e},a.apply(null,arguments)}n.d(t,{A:()=>a})},2892:(e,t,n)=>{"use strict";function a(e,t){return a=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(e,t){return e.__proto__=t,e},a(e,t)}function r(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,a(e,t)}n.d(t,{A:()=>r})},8587:(e,t,n)=>{"use strict";function a(e,t){if(null==e)return{};var n={};for(var a in e)if({}.hasOwnProperty.call(e,a)){if(t.includes(a))continue;n[a]=e[a]}return n}n.d(t,{A:()=>a})},1561:(e,t,n)=>{"use strict";n.d(t,{A:()=>o});var a=!0,r="Invariant failed";function o(e,t){if(!e){if(a)throw new Error(r);var n="function"==typeof t?t():t,o=n?"".concat(r,": ").concat(n):r;throw new Error(o)}}},2654:e=>{"use strict";e.exports={}},4054:e=>{"use strict";e.exports=JSON.parse('{"/docs/0.16.0/blog-329":{"__comp":"a6aa9e1f","__context":{"plugin":"1c41eae2"},"sidebar":"814f3328","items":[{"content":"f87e687e"},{"content":"20e2ece2"},{"content":"5058a078"},{"content":"8417e7a5"},{"content":"23f93eeb"}],"metadata":"46076c8b"},"/docs/0.16.0/blog/archive-230":{"__comp":"9e4087bc","__context":{"plugin":"1c41eae2"},"archive":"575d1ad6"},"/docs/0.16.0/blog/breaking-the-boundary-between-sql-and-nosql-ed2":{"__comp":"ccc49370","__context":{"plugin":"1c41eae2"},"sidebar":"814f3328","content":"7d170ab0"},"/docs/0.16.0/blog/release-v0.14-ae9":{"__comp":"ccc49370","__context":{"plugin":"1c41eae2"},"sidebar":"814f3328","content":"234733fd"},"/docs/0.16.0/blog/release-v0.15-628":{"__comp":"ccc49370","__context":{"plugin":"1c41eae2"},"sidebar":"814f3328","content":"c5c08033"},"/docs/0.16.0/blog/revolutionizing-databases-by-unifying-query-interfaces-bfc":{"__comp":"ccc49370","__context":{"plugin":"1c41eae2"},"sidebar":"814f3328","content":"772fc39d"},"/docs/0.16.0/blog/tags-a26":{"__comp":"01a85c17","__context":{"plugin":"1c41eae2"},"sidebar":"814f3328","tags":"75880d90"},"/docs/0.16.0/blog/tags/automation-b16":{"__comp":"6875c492","__context":{"plugin":"1c41eae2"},"sidebar":"814f3328","items":[{"content":"5058a078"}],"tag":"16682cd3","listMetadata":"7f479c52"},"/docs/0.16.0/blog/tags/chat-gpt-44c":{"__comp":"6875c492","__context":{"plugin":"1c41eae2"},"sidebar":"814f3328","items":[{"content":"5058a078"}],"tag":"c34cc4c9","listMetadata":"ca8fbf24"},"/docs/0.16.0/blog/tags/database-ef3":{"__comp":"6875c492","__context":{"plugin":"1c41eae2"},"sidebar":"814f3328","items":[{"content":"20e2ece2"},{"content":"5058a078"},{"content":"8417e7a5"}],"tag":"ec49082b","listMetadata":"9c7b888e"},"/docs/0.16.0/blog/tags/documentation-26a":{"__comp":"6875c492","__context":{"plugin":"1c41eae2"},"sidebar":"814f3328","items":[{"content":"5058a078"}],"tag":"7538b401","listMetadata":"723607d1"},"/docs/0.16.0/blog/tags/gluesql-cad":{"__comp":"6875c492","__context":{"plugin":"1c41eae2"},"sidebar":"814f3328","items":[{"content":"20e2ece2"}],"tag":"382b9f11","listMetadata":"425cb3cb"},"/docs/0.16.0/blog/tags/nosql-44a":{"__comp":"6875c492","__context":{"plugin":"1c41eae2"},"sidebar":"814f3328","items":[{"content":"8417e7a5"}],"tag":"47e70afa","listMetadata":"c3b79ba0"},"/docs/0.16.0/blog/tags/proposal-897":{"__comp":"6875c492","__context":{"plugin":"1c41eae2"},"sidebar":"814f3328","items":[{"content":"20e2ece2"}],"tag":"76bcd116","listMetadata":"98184455"},"/docs/0.16.0/blog/tags/query-interface-958":{"__comp":"6875c492","__context":{"plugin":"1c41eae2"},"sidebar":"814f3328","items":[{"content":"20e2ece2"}],"tag":"dd9db7c1","listMetadata":"6d2a6c9a"},"/docs/0.16.0/blog/tags/release-note-356":{"__comp":"6875c492","__context":{"plugin":"1c41eae2"},"sidebar":"814f3328","items":[{"content":"f87e687e"},{"content":"23f93eeb"}],"tag":"29fadaa3","listMetadata":"104749c9"},"/docs/0.16.0/blog/tags/sql-0fc":{"__comp":"6875c492","__context":{"plugin":"1c41eae2"},"sidebar":"814f3328","items":[{"content":"8417e7a5"}],"tag":"ec040517","listMetadata":"045be9fd"},"/docs/0.16.0/blog/tags/tdd-547":{"__comp":"6875c492","__context":{"plugin":"1c41eae2"},"sidebar":"814f3328","items":[{"content":"5058a078"}],"tag":"3ee3a370","listMetadata":"2149662b"},"/docs/0.16.0/blog/tags/test-driven-documentation-bc0":{"__comp":"6875c492","__context":{"plugin":"1c41eae2"},"sidebar":"814f3328","items":[{"content":"5058a078"}],"tag":"107910e9","listMetadata":"9edb318c"},"/docs/0.16.0/blog/tags/v-0-14-b27":{"__comp":"6875c492","__context":{"plugin":"1c41eae2"},"sidebar":"814f3328","items":[{"content":"23f93eeb"}],"tag":"2bb892db","listMetadata":"a87d47f1"},"/docs/0.16.0/blog/tags/v-0-15-26e":{"__comp":"6875c492","__context":{"plugin":"1c41eae2"},"sidebar":"814f3328","items":[{"content":"f87e687e"}],"tag":"f11e9837","listMetadata":"cba69ead"},"/docs/0.16.0/blog/test-driven-documentation-96f":{"__comp":"ccc49370","__context":{"plugin":"1c41eae2"},"sidebar":"814f3328","content":"25196878"},"/docs/0.16.0/-0d5":{"__comp":"1be78505","__context":{"plugin":"1e4e1fb6"},"versionMetadata":"935f2afb"},"/docs/0.16.0/-c45":{"__comp":"17896441","content":"c377a04b"},"/docs/0.16.0/ast-builder/expressions/conditional-455":{"__comp":"17896441","content":"a4bc1622"},"/docs/0.16.0/ast-builder/expressions/nested-dec":{"__comp":"17896441","content":"5df6e7df"},"/docs/0.16.0/ast-builder/expressions/operator-based-f0e":{"__comp":"17896441","content":"44954150"},"/docs/0.16.0/ast-builder/expressions/pattern-matching-027":{"__comp":"17896441","content":"2b265210"},"/docs/0.16.0/ast-builder/expressions/value-checking-53b":{"__comp":"17896441","content":"b6bceaff"},"/docs/0.16.0/ast-builder/functions/date-&-time/conversion-8cb":{"__comp":"17896441","content":"acfabe81"},"/docs/0.16.0/ast-builder/functions/date-&-time/current-date-and-time-cc6":{"__comp":"17896441","content":"8c7569e5"},"/docs/0.16.0/ast-builder/functions/date-&-time/date-and-time-extraction-4a1":{"__comp":"17896441","content":"7ea7f008"},"/docs/0.16.0/ast-builder/functions/date-&-time/formatting-2e7":{"__comp":"17896441","content":"463dc00f"},"/docs/0.16.0/ast-builder/functions/geometry/coordinate-extraction-0b9":{"__comp":"17896441","content":"f6ca3de5"},"/docs/0.16.0/ast-builder/functions/geometry/distance-calculation-842":{"__comp":"17896441","content":"89fc5f00"},"/docs/0.16.0/ast-builder/functions/geometry/point-creation-a22":{"__comp":"17896441","content":"a6b6486c"},"/docs/0.16.0/ast-builder/functions/list-&-map/list-and-map-concatenation-fa4":{"__comp":"17896441","content":"81bf07f5"},"/docs/0.16.0/ast-builder/functions/list-&-map/list-manipulation-ad0":{"__comp":"17896441","content":"a2ab2bad"},"/docs/0.16.0/ast-builder/functions/math/basic-arithmetic-e45":{"__comp":"17896441","content":"9c5158ac"},"/docs/0.16.0/ast-builder/functions/math/conversion-de5":{"__comp":"17896441","content":"02aa4531"},"/docs/0.16.0/ast-builder/functions/math/logarithmic-and-exponential-047":{"__comp":"17896441","content":"980f8d5e"},"/docs/0.16.0/ast-builder/functions/math/rounding-430":{"__comp":"17896441","content":"1ce64703"},"/docs/0.16.0/ast-builder/functions/math/special-mathematical-06e":{"__comp":"17896441","content":"89196f72"},"/docs/0.16.0/ast-builder/functions/math/trigonometric-2f4":{"__comp":"17896441","content":"c5e834bc"},"/docs/0.16.0/ast-builder/functions/others/null-handling-600":{"__comp":"17896441","content":"078a6308"},"/docs/0.16.0/ast-builder/functions/others/type-conversion-c9d":{"__comp":"17896441","content":"26c0a43c"},"/docs/0.16.0/ast-builder/functions/others/unique-identifier-0db":{"__comp":"17896441","content":"d5aa49f9"},"/docs/0.16.0/ast-builder/functions/text/case-conversion-51f":{"__comp":"17896441","content":"d7a493e6"},"/docs/0.16.0/ast-builder/functions/text/character-conversion-8df":{"__comp":"17896441","content":"3cfbc8af"},"/docs/0.16.0/ast-builder/functions/text/padding-a12":{"__comp":"17896441","content":"07294b24"},"/docs/0.16.0/ast-builder/functions/text/position-and-indexing-24f":{"__comp":"17896441","content":"f9553497"},"/docs/0.16.0/ast-builder/functions/text/text-manipulation-5fa":{"__comp":"17896441","content":"1cdac986"},"/docs/0.16.0/ast-builder/functions/text/trimming-025":{"__comp":"17896441","content":"02bfc02d"},"/docs/0.16.0/ast-builder/intro-a6e":{"__comp":"17896441","content":"4add0c6c"},"/docs/0.16.0/ast-builder/statements/data-manipulation/deleting-data-5a9":{"__comp":"17896441","content":"376759eb"},"/docs/0.16.0/ast-builder/statements/data-manipulation/inserting-data-924":{"__comp":"17896441","content":"bac2c42d"},"/docs/0.16.0/ast-builder/statements/data-manipulation/updating-data-727":{"__comp":"17896441","content":"037683de"},"/docs/0.16.0/ast-builder/statements/querying/creating-derived-subqueries-c6d":{"__comp":"17896441","content":"017e736e"},"/docs/0.16.0/ast-builder/statements/querying/data-aggregation-116":{"__comp":"17896441","content":"b3de9677"},"/docs/0.16.0/ast-builder/statements/querying/data-injection-745":{"__comp":"17896441","content":"4be897c9"},"/docs/0.16.0/ast-builder/statements/querying/data-joining-caf":{"__comp":"17896441","content":"e5f53749"},"/docs/0.16.0/ast-builder/statements/querying/data-selection-and-projection-88b":{"__comp":"17896441","content":"f914cfe8"},"/docs/0.16.0/ast-builder/statements/querying/data-sorting-and-limiting-64f":{"__comp":"17896441","content":"16815c2a"},"/docs/0.16.0/ast-builder/statements/querying/fetching-data-from-storage-1ed":{"__comp":"17896441","content":"ee244d12"},"/docs/0.16.0/ast-builder/statements/querying/using-preloaded-data-ec8":{"__comp":"17896441","content":"d97b7d4d"},"/docs/0.16.0/getting-started/cli-2ff":{"__comp":"17896441","content":"1c93e70c"},"/docs/0.16.0/getting-started/javascript-web-040":{"__comp":"17896441","content":"e10f7c24"},"/docs/0.16.0/getting-started/nodejs-af8":{"__comp":"17896441","content":"01a12966"},"/docs/0.16.0/getting-started/rust-43e":{"__comp":"17896441","content":"72c409f7"},"/docs/0.16.0/sql-syntax/data-types/boolean-a91":{"__comp":"17896441","content":"e68f8ad6"},"/docs/0.16.0/sql-syntax/data-types/bytea-f2a":{"__comp":"17896441","content":"1798d0b3"},"/docs/0.16.0/sql-syntax/data-types/date-b96":{"__comp":"17896441","content":"a5971d1a"},"/docs/0.16.0/sql-syntax/data-types/decimal-0a5":{"__comp":"17896441","content":"0b621d16"},"/docs/0.16.0/sql-syntax/data-types/float-2cf":{"__comp":"17896441","content":"f33f2c05"},"/docs/0.16.0/sql-syntax/data-types/inet-f37":{"__comp":"17896441","content":"a9e26133"},"/docs/0.16.0/sql-syntax/data-types/integers-173":{"__comp":"17896441","content":"aa1cf9a2"},"/docs/0.16.0/sql-syntax/data-types/interval-7c6":{"__comp":"17896441","content":"6ff6e7c9"},"/docs/0.16.0/sql-syntax/data-types/list-438":{"__comp":"17896441","content":"2c0d2b92"},"/docs/0.16.0/sql-syntax/data-types/map-b8c":{"__comp":"17896441","content":"50818478"},"/docs/0.16.0/sql-syntax/data-types/text-2f3":{"__comp":"17896441","content":"d077f377"},"/docs/0.16.0/sql-syntax/data-types/time-fb4":{"__comp":"17896441","content":"ff7b8d8e"},"/docs/0.16.0/sql-syntax/data-types/timestamp-62b":{"__comp":"17896441","content":"a8d11699"},"/docs/0.16.0/sql-syntax/data-types/uuid-ea3":{"__comp":"17896441","content":"bfb64759"},"/docs/0.16.0/sql-syntax/functions/datetime/extract-5be":{"__comp":"17896441","content":"4f675ae9"},"/docs/0.16.0/sql-syntax/functions/datetime/format-afd":{"__comp":"17896441","content":"f18bbaf6"},"/docs/0.16.0/sql-syntax/functions/datetime/now-17b":{"__comp":"17896441","content":"98306a23"},"/docs/0.16.0/sql-syntax/functions/datetime/to-date-6b1":{"__comp":"17896441","content":"928a5d6f"},"/docs/0.16.0/sql-syntax/functions/datetime/to-time-88f":{"__comp":"17896441","content":"a7153b78"},"/docs/0.16.0/sql-syntax/functions/datetime/to-timestamp-168":{"__comp":"17896441","content":"c2e5ab4f"},"/docs/0.16.0/sql-syntax/functions/geometry/calc-distance-e74":{"__comp":"17896441","content":"aff456d7"},"/docs/0.16.0/sql-syntax/functions/geometry/get-x-c71":{"__comp":"17896441","content":"9a3e57da"},"/docs/0.16.0/sql-syntax/functions/geometry/get-y-9cc":{"__comp":"17896441","content":"2a4d41ed"},"/docs/0.16.0/sql-syntax/functions/geometry/point-0a6":{"__comp":"17896441","content":"1a3daba8"},"/docs/0.16.0/sql-syntax/functions/list-map/append-3c6":{"__comp":"17896441","content":"0c18287f"},"/docs/0.16.0/sql-syntax/functions/list-map/concat-8ee":{"__comp":"17896441","content":"cf518063"},"/docs/0.16.0/sql-syntax/functions/list-map/prepend-104":{"__comp":"17896441","content":"77cc432a"},"/docs/0.16.0/sql-syntax/functions/list-map/slice-ce3":{"__comp":"17896441","content":"d0ba620f"},"/docs/0.16.0/sql-syntax/functions/list-map/splice-1f9":{"__comp":"17896441","content":"4d9df5b1"},"/docs/0.16.0/sql-syntax/functions/math/abs-ae9":{"__comp":"17896441","content":"5a8c7729"},"/docs/0.16.0/sql-syntax/functions/math/acos-2c5":{"__comp":"17896441","content":"6ba4a510"},"/docs/0.16.0/sql-syntax/functions/math/asin-9cb":{"__comp":"17896441","content":"68c17ba1"},"/docs/0.16.0/sql-syntax/functions/math/atan-ad4":{"__comp":"17896441","content":"ba43b2d5"},"/docs/0.16.0/sql-syntax/functions/math/ceil-6f8":{"__comp":"17896441","content":"56ccfc32"},"/docs/0.16.0/sql-syntax/functions/math/cos-776":{"__comp":"17896441","content":"2f7bd5c8"},"/docs/0.16.0/sql-syntax/functions/math/degrees-5fd":{"__comp":"17896441","content":"c97e0540"},"/docs/0.16.0/sql-syntax/functions/math/div-ea6":{"__comp":"17896441","content":"920bdc78"},"/docs/0.16.0/sql-syntax/functions/math/exp-a42":{"__comp":"17896441","content":"faca410e"},"/docs/0.16.0/sql-syntax/functions/math/floor-cef":{"__comp":"17896441","content":"1b8ca8c3"},"/docs/0.16.0/sql-syntax/functions/math/gcd-95e":{"__comp":"17896441","content":"cdaafcc9"},"/docs/0.16.0/sql-syntax/functions/math/lcm-394":{"__comp":"17896441","content":"e4f709d1"},"/docs/0.16.0/sql-syntax/functions/math/ln-b8a":{"__comp":"17896441","content":"ae3eef3e"},"/docs/0.16.0/sql-syntax/functions/math/log-4b4":{"__comp":"17896441","content":"db0d9cb2"},"/docs/0.16.0/sql-syntax/functions/math/log10-589":{"__comp":"17896441","content":"afebe5f1"},"/docs/0.16.0/sql-syntax/functions/math/log2-002":{"__comp":"17896441","content":"f1257df2"},"/docs/0.16.0/sql-syntax/functions/math/mod-d1b":{"__comp":"17896441","content":"4a9d0f4c"},"/docs/0.16.0/sql-syntax/functions/math/pi-d03":{"__comp":"17896441","content":"eceb3b9b"},"/docs/0.16.0/sql-syntax/functions/math/power-e3b":{"__comp":"17896441","content":"a7e6874c"},"/docs/0.16.0/sql-syntax/functions/math/radians-f1b":{"__comp":"17896441","content":"160faf1d"},"/docs/0.16.0/sql-syntax/functions/math/rand-fd2":{"__comp":"17896441","content":"385623dc"},"/docs/0.16.0/sql-syntax/functions/math/round-9da":{"__comp":"17896441","content":"7e0ce508"},"/docs/0.16.0/sql-syntax/functions/math/sign-3f7":{"__comp":"17896441","content":"6870612e"},"/docs/0.16.0/sql-syntax/functions/math/sin-b9a":{"__comp":"17896441","content":"9a1c8bc6"},"/docs/0.16.0/sql-syntax/functions/math/sqrt-287":{"__comp":"17896441","content":"5242ac2d"},"/docs/0.16.0/sql-syntax/functions/math/tan-69c":{"__comp":"17896441","content":"85afcbde"},"/docs/0.16.0/sql-syntax/functions/others/cast-387":{"__comp":"17896441","content":"bb43b8ce"},"/docs/0.16.0/sql-syntax/functions/others/generate-uuid-e66":{"__comp":"17896441","content":"0ea64360"},"/docs/0.16.0/sql-syntax/functions/others/ifnull-a75":{"__comp":"17896441","content":"fa5466f2"},"/docs/0.16.0/sql-syntax/functions/text/ascii-cbf":{"__comp":"17896441","content":"e06425d1"},"/docs/0.16.0/sql-syntax/functions/text/chr-570":{"__comp":"17896441","content":"8cf2dd9c"},"/docs/0.16.0/sql-syntax/functions/text/concat-95d":{"__comp":"17896441","content":"a470b55c"},"/docs/0.16.0/sql-syntax/functions/text/concat-ws-f26":{"__comp":"17896441","content":"c5b25a7c"},"/docs/0.16.0/sql-syntax/functions/text/find-idx-736":{"__comp":"17896441","content":"d4251823"},"/docs/0.16.0/sql-syntax/functions/text/initcap-0f6":{"__comp":"17896441","content":"06322d53"},"/docs/0.16.0/sql-syntax/functions/text/left-9eb":{"__comp":"17896441","content":"dafe2799"},"/docs/0.16.0/sql-syntax/functions/text/lower-e33":{"__comp":"17896441","content":"81f6aa2c"},"/docs/0.16.0/sql-syntax/functions/text/lpad-a51":{"__comp":"17896441","content":"97081ee7"},"/docs/0.16.0/sql-syntax/functions/text/ltrim-8e7":{"__comp":"17896441","content":"007e0817"},"/docs/0.16.0/sql-syntax/functions/text/position-ffa":{"__comp":"17896441","content":"15868c40"},"/docs/0.16.0/sql-syntax/functions/text/repeat-44f":{"__comp":"17896441","content":"b57ca7d5"},"/docs/0.16.0/sql-syntax/functions/text/reverse-6ec":{"__comp":"17896441","content":"ae967838"},"/docs/0.16.0/sql-syntax/functions/text/right-c35":{"__comp":"17896441","content":"5eabd930"},"/docs/0.16.0/sql-syntax/functions/text/rpad-dd5":{"__comp":"17896441","content":"7457c448"},"/docs/0.16.0/sql-syntax/functions/text/rtrim-ab5":{"__comp":"17896441","content":"c9d1eb08"},"/docs/0.16.0/sql-syntax/functions/text/substr-389":{"__comp":"17896441","content":"d8746e52"},"/docs/0.16.0/sql-syntax/functions/text/trim-f09":{"__comp":"17896441","content":"41718851"},"/docs/0.16.0/sql-syntax/functions/text/upper-9fe":{"__comp":"17896441","content":"b7661aba"},"/docs/0.16.0/sql-syntax/intro-4ad":{"__comp":"17896441","content":"31526b20"},"/docs/0.16.0/sql-syntax/statements/data-definition/alter-table-426":{"__comp":"17896441","content":"0c94c658"},"/docs/0.16.0/sql-syntax/statements/data-definition/create-index-15a":{"__comp":"17896441","content":"0544f90b"},"/docs/0.16.0/sql-syntax/statements/data-definition/create-table-db9":{"__comp":"17896441","content":"86a1f821"},"/docs/0.16.0/sql-syntax/statements/data-definition/drop-index-4b8":{"__comp":"17896441","content":"4aa001c0"},"/docs/0.16.0/sql-syntax/statements/data-definition/drop-table-d17":{"__comp":"17896441","content":"402da695"},"/docs/0.16.0/sql-syntax/statements/data-manipulation/delete-446":{"__comp":"17896441","content":"92dd0956"},"/docs/0.16.0/sql-syntax/statements/data-manipulation/insert-d9a":{"__comp":"17896441","content":"df2eb7da"},"/docs/0.16.0/sql-syntax/statements/data-manipulation/update-67b":{"__comp":"17896441","content":"8be9dc67"},"/docs/0.16.0/sql-syntax/statements/metadata/data-dictionary-2d3":{"__comp":"17896441","content":"6c5232c2"},"/docs/0.16.0/sql-syntax/statements/metadata/show-tables-864":{"__comp":"17896441","content":"c30ee527"},"/docs/0.16.0/sql-syntax/statements/querying/aggregation-dc5":{"__comp":"17896441","content":"3245f64b"},"/docs/0.16.0/sql-syntax/statements/querying/join-217":{"__comp":"17896441","content":"dc8f2f6c"},"/docs/0.16.0/sql-syntax/statements/querying/limit-437":{"__comp":"17896441","content":"b7da1136"},"/docs/0.16.0/sql-syntax/statements/querying/schemaless-ee2":{"__comp":"17896441","content":"7310a4fe"},"/docs/0.16.0/sql-syntax/statements/querying/where-9f4":{"__comp":"17896441","content":"2d9479c4"},"/docs/0.16.0/sql-syntax/statements/transaction-f5c":{"__comp":"17896441","content":"e158c27a"},"/docs/0.16.0/storages/developing-custom-storages/intro-6c1":{"__comp":"17896441","content":"c251e734"},"/docs/0.16.0/storages/developing-custom-storages/store-traits/alter-table-aad":{"__comp":"17896441","content":"194e858c"},"/docs/0.16.0/storages/developing-custom-storages/store-traits/custom-function-015":{"__comp":"17896441","content":"83b912d4"},"/docs/0.16.0/storages/developing-custom-storages/store-traits/custom-function-mut-056":{"__comp":"17896441","content":"44f79c8d"},"/docs/0.16.0/storages/developing-custom-storages/store-traits/index-mut-9d8":{"__comp":"17896441","content":"5cdfb1f2"},"/docs/0.16.0/storages/developing-custom-storages/store-traits/index-trait-26c":{"__comp":"17896441","content":"d941076d"},"/docs/0.16.0/storages/developing-custom-storages/store-traits/metadata-1eb":{"__comp":"17896441","content":"e329d2fa"},"/docs/0.16.0/storages/developing-custom-storages/store-traits/store-0ad":{"__comp":"17896441","content":"482a391c"},"/docs/0.16.0/storages/developing-custom-storages/store-traits/store-mut-862":{"__comp":"17896441","content":"ebe12d94"},"/docs/0.16.0/storages/developing-custom-storages/store-traits/transaction-12b":{"__comp":"17896441","content":"488157d7"},"/docs/0.16.0/storages/developing-custom-storages/using-test-suite-5ee":{"__comp":"17896441","content":"345c600d"},"/docs/0.16.0/storages/intro-6dd":{"__comp":"17896441","content":"b209ab8a"},"/docs/0.16.0/storages/supported-storages/composite-storage-3ce":{"__comp":"17896441","content":"67d1434e"},"/docs/0.16.0/storages/supported-storages/csv-storage-353":{"__comp":"17896441","content":"6a35a4d8"},"/docs/0.16.0/storages/supported-storages/idb-storage-8c8":{"__comp":"17896441","content":"952dfacb"},"/docs/0.16.0/storages/supported-storages/json-storage-bb2":{"__comp":"17896441","content":"3961e600"},"/docs/0.16.0/storages/supported-storages/memory-storage-e63":{"__comp":"17896441","content":"6e772156"},"/docs/0.16.0/storages/supported-storages/parquet-storage-d14":{"__comp":"17896441","content":"f7912ff8"},"/docs/0.16.0/storages/supported-storages/shared-memory-storage-632":{"__comp":"17896441","content":"e46b95eb"},"/docs/0.16.0/storages/supported-storages/sled-storage-652":{"__comp":"17896441","content":"8d6e802b"},"/docs/0.16.0/storages/supported-storages/web-storage-7d2":{"__comp":"17896441","content":"edb9b0b8"}}')}},e=>{e.O(0,[1869],(()=>{return t=8536,e(e.s=t);var t}));e.O()}]); \ No newline at end of file diff --git a/docs/0.16.0/assets/js/main.d2f0168d.js.LICENSE.txt b/docs/0.16.0/assets/js/main.d2f0168d.js.LICENSE.txt new file mode 100644 index 00000000..eb75d691 --- /dev/null +++ b/docs/0.16.0/assets/js/main.d2f0168d.js.LICENSE.txt @@ -0,0 +1,63 @@ +/* +object-assign +(c) Sindre Sorhus +@license MIT +*/ + +/* NProgress, (c) 2013, 2014 Rico Sta. Cruz - http://ricostacruz.com/nprogress + * @license MIT */ + +/** + * @license React + * use-sync-external-store-shim.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * Prism: Lightweight, robust, elegant syntax highlighting + * + * @license MIT <https://opensource.org/licenses/MIT> + * @author Lea Verou <https://lea.verou.me> + * @namespace + * @public + */ + +/** @license React v0.20.2 + * scheduler.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** @license React v16.13.1 + * react-is.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** @license React v17.0.2 + * react-dom.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** @license React v17.0.2 + * react.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ diff --git a/docs/0.16.0/assets/js/runtime~main.0eac1086.js b/docs/0.16.0/assets/js/runtime~main.0eac1086.js new file mode 100644 index 00000000..137cdf0d --- /dev/null +++ b/docs/0.16.0/assets/js/runtime~main.0eac1086.js @@ -0,0 +1 @@ +(()=>{"use strict";var e,a,c,d,f,b={},t={};function r(e){var a=t[e];if(void 0!==a)return a.exports;var c=t[e]={exports:{}};return b[e].call(c.exports,c,c.exports,r),c.exports}r.m=b,e=[],r.O=(a,c,d,f)=>{if(!c){var b=1/0;for(i=0;i<e.length;i++){c=e[i][0],d=e[i][1],f=e[i][2];for(var t=!0,o=0;o<c.length;o++)(!1&f||b>=f)&&Object.keys(r.O).every((e=>r.O[e](c[o])))?c.splice(o--,1):(t=!1,f<b&&(b=f));if(t){e.splice(i--,1);var n=d();void 0!==n&&(a=n)}}return a}f=f||0;for(var i=e.length;i>0&&e[i-1][2]>f;i--)e[i]=e[i-1];e[i]=[c,d,f]},r.n=e=>{var a=e&&e.__esModule?()=>e.default:()=>e;return r.d(a,{a:a}),a},c=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,r.t=function(e,d){if(1&d&&(e=this(e)),8&d)return e;if("object"==typeof e&&e){if(4&d&&e.__esModule)return e;if(16&d&&"function"==typeof e.then)return e}var f=Object.create(null);r.r(f);var b={};a=a||[null,c({}),c([]),c(c)];for(var t=2&d&&e;"object"==typeof t&&!~a.indexOf(t);t=c(t))Object.getOwnPropertyNames(t).forEach((a=>b[a]=()=>e[a]));return b.default=()=>e,r.d(f,b),f},r.d=(e,a)=>{for(var c in a)r.o(a,c)&&!r.o(e,c)&&Object.defineProperty(e,c,{enumerable:!0,get:a[c]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce(((a,c)=>(r.f[c](e,a),a)),[])),r.u=e=>"assets/js/"+({8:"345c600d",79:"01a12966",85:"ff7b8d8e",106:"045be9fd",108:"6e772156",126:"02aa4531",129:"db0d9cb2",133:"a87d47f1",262:"d941076d",285:"6d2a6c9a",306:"ec49082b",321:"e158c27a",390:"1ce64703",521:"385623dc",550:"44f79c8d",666:"920bdc78",732:"a2ab2bad",770:"402da695",805:"e329d2fa",827:"7457c448",969:"7d170ab0",1007:"f11e9837",1202:"dafe2799",1219:"0544f90b",1226:"ee244d12",1274:"d4251823",1296:"68c17ba1",1403:"f914cfe8",1416:"482a391c",1433:"cdaafcc9",1459:"2d9479c4",1485:"f18bbaf6",1489:"9c7b888e",1502:"df2eb7da",1553:"2149662b",1570:"c3b79ba0",1656:"a4bc1622",1661:"037683de",1717:"1c41eae2",1747:"6ff6e7c9",1838:"afebe5f1",1947:"e68f8ad6",1978:"81bf07f5",1990:"2bb892db",2012:"b6bceaff",2025:"ebe12d94",2100:"c5c08033",2119:"c9d1eb08",2160:"faca410e",2245:"c2e5ab4f",2323:"44954150",2450:"acfabe81",2468:"8d6e802b",2495:"f9553497",2570:"160faf1d",2591:"ae3eef3e",2605:"85afcbde",2636:"8cf2dd9c",2710:"aff456d7",2711:"9e4087bc",2735:"dc8f2f6c",2758:"0c18287f",2883:"e46b95eb",2920:"31526b20",2997:"25196878",3055:"07294b24",3071:"a7153b78",3117:"6ba4a510",3216:"9a3e57da",3249:"ccc49370",3268:"75880d90",3274:"d5aa49f9",3352:"d97b7d4d",3386:"b209ab8a",3497:"dd9db7c1",3631:"007e0817",3679:"fa5466f2",3772:"1b8ca8c3",3783:"b7661aba",3823:"a6b6486c",3826:"7310a4fe",3848:"2f7bd5c8",3892:"a5971d1a",3995:"376759eb",4073:"a9e26133",4082:"47e70afa",4192:"6870612e",4217:"7ea7f008",4222:"5242ac2d",4229:"72c409f7",4234:"194e858c",4253:"e4f709d1",4303:"463dc00f",4386:"5cdfb1f2",4467:"edb9b0b8",4541:"98184455",4550:"29fadaa3",4602:"b7da1136",4646:"89fc5f00",4667:"5a8c7729",4704:"e06425d1",4726:"1a3daba8",4784:"4f675ae9",4813:"6875c492",4845:"67d1434e",4848:"980f8d5e",4887:"0c94c658",4972:"06322d53",5e3:"d8746e52",5006:"bb43b8ce",5010:"3ee3a370",5062:"2a4d41ed",5086:"92dd0956",5120:"23f93eeb",5138:"16682cd3",5169:"46076c8b",5183:"017e736e",5334:"d0ba620f",5363:"aa1cf9a2",5380:"16815c2a",5427:"c34cc4c9",5535:"98306a23",5666:"d7a493e6",5732:"078a6308",5742:"c377a04b",5760:"9a1c8bc6",5773:"8be9dc67",5834:"a8d11699",6061:"488157d7",6088:"50818478",6098:"56ccfc32",6204:"c30ee527",6205:"8c7569e5",6247:"c5b25a7c",6251:"cf518063",6257:"2b265210",6276:"1c93e70c",6528:"15868c40",6554:"ba43b2d5",6571:"952dfacb",6576:"928a5d6f",6585:"1798d0b3",6637:"76bcd116",6704:"772fc39d",6738:"d077f377",6803:"e10f7c24",6826:"83b912d4",6834:"f7912ff8",6858:"02bfc02d",6867:"77cc432a",6926:"9c5158ac",6995:"89196f72",7033:"97081ee7",7096:"41718851",7135:"6c5232c2",7179:"c251e734",7248:"1cdac986",7278:"f1257df2",7297:"723607d1",7309:"f33f2c05",7319:"b3de9677",7433:"3cfbc8af",7436:"eceb3b9b",7458:"ec040517",7472:"814f3328",7514:"5df6e7df",7532:"f6ca3de5",7540:"4d9df5b1",7637:"107910e9",7643:"a6aa9e1f",7662:"104749c9",7700:"c5e834bc",7722:"7e0ce508",7794:"bfb64759",7807:"ca8fbf24",7814:"0ea64360",7879:"b57ca7d5",7889:"1e4e1fb6",8032:"9edb318c",8053:"234733fd",8059:"0b621d16",8209:"01a85c17",8242:"a470b55c",8317:"4aa001c0",8401:"17896441",8439:"6a35a4d8",8465:"e5f53749",8505:"5058a078",8581:"935f2afb",8590:"c97e0540",8604:"bac2c42d",8681:"8417e7a5",8707:"425cb3cb",8714:"1be78505",8738:"a7e6874c",8799:"26c0a43c",8819:"2c0d2b92",9033:"81f6aa2c",9040:"4a9d0f4c",9070:"7f479c52",9186:"86a1f821",9251:"f87e687e",9309:"7538b401",9327:"3245f64b",9350:"4be897c9",9445:"382b9f11",9544:"cba69ead",9564:"4add0c6c",9565:"3961e600",9612:"5eabd930",9700:"575d1ad6",9876:"ae967838",9957:"20e2ece2"}[e]||e)+"."+{8:"d35af627",79:"469b19f8",85:"2839820c",106:"bc59c80a",108:"de8699ba",126:"17b335fe",129:"c1e2f54b",133:"638107c7",262:"e217ef5e",285:"899740c3",306:"0c5dd593",321:"75d2740d",390:"168baa89",521:"79e6e52e",550:"0eabe5cf",666:"764abce5",732:"24b45834",770:"dca958f2",805:"594a299b",827:"8eae7baa",969:"638674ff",1007:"fbbfe220",1202:"0365f5ae",1219:"ccc9e299",1226:"81f504bd",1274:"1b779bc7",1296:"56cc7f22",1403:"0c3fe5c5",1416:"b8ab4399",1433:"085c239c",1459:"60ec37b5",1485:"3a12296c",1489:"0f19b601",1502:"6039d156",1553:"86af6d60",1570:"05e34179",1656:"56c7a466",1661:"b9938f31",1717:"66378d8d",1747:"34518733",1774:"e76e375b",1838:"5fe2a23f",1947:"c1a8db19",1978:"ce836a1d",1990:"7dbc4c68",2012:"19fa54f6",2025:"e9202909",2100:"3258f7d1",2119:"85ddc867",2160:"0cb58136",2245:"ab7e6240",2323:"17b33b16",2450:"2547b40d",2468:"dffe0fdb",2495:"6168470e",2570:"05a9000e",2591:"eb463894",2605:"5593c8d3",2636:"d59af323",2710:"8f09df74",2711:"fd7711ba",2735:"1fb3dce7",2758:"2d4dde49",2883:"b729c545",2920:"042cabc1",2997:"ca24ae51",3055:"663c5d97",3071:"a2b5a6f6",3117:"b8825408",3216:"6cf35ab2",3249:"db557050",3268:"d5ebfb17",3274:"6dad4890",3352:"9b38cbbf",3386:"cf366253",3497:"95fe8d2d",3631:"64d185e0",3679:"c7b13c43",3772:"4358a704",3783:"2998c510",3823:"7066e9bb",3826:"cb7c0f12",3848:"56754015",3892:"0ab74105",3995:"a26c2de9",4073:"7429af4a",4082:"c24efe3f",4192:"6f228bb6",4217:"1e86f06b",4222:"16055ebb",4229:"37981358",4234:"98c96ae7",4253:"622e5fc6",4303:"a9cd6d15",4386:"9bdca8fe",4467:"52075b0f",4541:"9f967dd2",4550:"5953c4d1",4602:"344a5231",4646:"a011da22",4667:"77c8d70b",4704:"7677941c",4726:"ac1ba8e8",4784:"2aee3ba3",4813:"c67f2e73",4845:"85b319c4",4848:"0a236b42",4887:"a5f781c3",4972:"4d22d233",5e3:"e4d0dc41",5006:"0fddfec9",5010:"68b8d0ad",5062:"52ff89d0",5086:"d500cc47",5120:"c9adc153",5138:"e744db6a",5169:"dd37858a",5183:"f5dc6055",5334:"f8ae8564",5363:"52828c0e",5380:"9ebfe213",5427:"56ce985b",5535:"b1ce97fe",5666:"f2613a57",5732:"4d53bdee",5742:"809da12b",5760:"dce511c1",5773:"6449ddb1",5834:"0e5d0034",6061:"4b4eebc3",6088:"556f0b73",6098:"2dcbb12d",6204:"527297e3",6205:"4214ccc3",6247:"95edb7f7",6251:"ebb43726",6257:"b10c2ab1",6276:"77ab6302",6528:"654d0d37",6554:"5ca14789",6571:"b6458afa",6576:"b84c0c0b",6585:"36e85a04",6637:"31f94fcd",6704:"44e54754",6738:"2c3c9edc",6803:"1537803d",6826:"ab8880e8",6834:"139c630a",6858:"c93d2576",6867:"d85baedd",6926:"353fe2b2",6995:"edb5fbb7",7033:"4d3ce296",7096:"37d8e0c9",7135:"fafd0f71",7179:"3fd3d58f",7248:"f465f273",7278:"c27413b8",7297:"e3c765d2",7309:"bece9048",7319:"5c877865",7433:"042652b0",7436:"bc074cbb",7458:"f0e83778",7472:"24525a8b",7514:"487902f2",7532:"1be337f5",7540:"71153059",7637:"5dfe754c",7643:"c5d6d672",7662:"09fc621f",7700:"7eb47f50",7722:"7eebaf2e",7794:"8ed694c2",7807:"d1ac6d6a",7814:"3dae4181",7879:"032ee46f",7889:"352993fe",8032:"9950535d",8053:"413dbe85",8059:"b92732eb",8209:"de44d5e4",8242:"c5b0f903",8317:"c8372f9f",8382:"3c17fd52",8401:"25d2eecf",8439:"35bcee7f",8465:"cd665626",8505:"d2f3c214",8581:"2f263db7",8590:"375c7725",8604:"f5a5b87a",8681:"dcd6c648",8707:"214e68a0",8714:"08a4249d",8738:"32075221",8799:"fc23d5e4",8809:"44c4a575",8819:"f8c85258",9033:"ee049a89",9040:"65b12999",9070:"1ff8ee6e",9186:"7ee13ee9",9251:"8a0ae88d",9309:"9467be0b",9327:"3f312bbc",9350:"e7b3c387",9445:"ecb346c2",9544:"8298012c",9564:"7ed8ffdc",9565:"447d8182",9612:"fbc0a29f",9700:"074a3068",9876:"0bc2b7aa",9957:"6327fef8"}[e]+".js",r.miniCssF=e=>{},r.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),r.o=(e,a)=>Object.prototype.hasOwnProperty.call(e,a),d={},f="docs:",r.l=(e,a,c,b)=>{if(d[e])d[e].push(a);else{var t,o;if(void 0!==c)for(var n=document.getElementsByTagName("script"),i=0;i<n.length;i++){var u=n[i];if(u.getAttribute("src")==e||u.getAttribute("data-webpack")==f+c){t=u;break}}t||(o=!0,(t=document.createElement("script")).charset="utf-8",t.timeout=120,r.nc&&t.setAttribute("nonce",r.nc),t.setAttribute("data-webpack",f+c),t.src=e),d[e]=[a];var l=(a,c)=>{t.onerror=t.onload=null,clearTimeout(s);var f=d[e];if(delete d[e],t.parentNode&&t.parentNode.removeChild(t),f&&f.forEach((e=>e(c))),a)return a(c)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:t}),12e4);t.onerror=l.bind(null,t.onerror),t.onload=l.bind(null,t.onload),o&&document.head.appendChild(t)}},r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.p="/docs/0.16.0/",r.gca=function(e){return e={17896441:"8401",25196878:"2997",41718851:"7096",44954150:"2323",50818478:"6088",98184455:"4541","345c600d":"8","01a12966":"79",ff7b8d8e:"85","045be9fd":"106","6e772156":"108","02aa4531":"126",db0d9cb2:"129",a87d47f1:"133",d941076d:"262","6d2a6c9a":"285",ec49082b:"306",e158c27a:"321","1ce64703":"390","385623dc":"521","44f79c8d":"550","920bdc78":"666",a2ab2bad:"732","402da695":"770",e329d2fa:"805","7457c448":"827","7d170ab0":"969",f11e9837:"1007",dafe2799:"1202","0544f90b":"1219",ee244d12:"1226",d4251823:"1274","68c17ba1":"1296",f914cfe8:"1403","482a391c":"1416",cdaafcc9:"1433","2d9479c4":"1459",f18bbaf6:"1485","9c7b888e":"1489",df2eb7da:"1502","2149662b":"1553",c3b79ba0:"1570",a4bc1622:"1656","037683de":"1661","1c41eae2":"1717","6ff6e7c9":"1747",afebe5f1:"1838",e68f8ad6:"1947","81bf07f5":"1978","2bb892db":"1990",b6bceaff:"2012",ebe12d94:"2025",c5c08033:"2100",c9d1eb08:"2119",faca410e:"2160",c2e5ab4f:"2245",acfabe81:"2450","8d6e802b":"2468",f9553497:"2495","160faf1d":"2570",ae3eef3e:"2591","85afcbde":"2605","8cf2dd9c":"2636",aff456d7:"2710","9e4087bc":"2711",dc8f2f6c:"2735","0c18287f":"2758",e46b95eb:"2883","31526b20":"2920","07294b24":"3055",a7153b78:"3071","6ba4a510":"3117","9a3e57da":"3216",ccc49370:"3249","75880d90":"3268",d5aa49f9:"3274",d97b7d4d:"3352",b209ab8a:"3386",dd9db7c1:"3497","007e0817":"3631",fa5466f2:"3679","1b8ca8c3":"3772",b7661aba:"3783",a6b6486c:"3823","7310a4fe":"3826","2f7bd5c8":"3848",a5971d1a:"3892","376759eb":"3995",a9e26133:"4073","47e70afa":"4082","6870612e":"4192","7ea7f008":"4217","5242ac2d":"4222","72c409f7":"4229","194e858c":"4234",e4f709d1:"4253","463dc00f":"4303","5cdfb1f2":"4386",edb9b0b8:"4467","29fadaa3":"4550",b7da1136:"4602","89fc5f00":"4646","5a8c7729":"4667",e06425d1:"4704","1a3daba8":"4726","4f675ae9":"4784","6875c492":"4813","67d1434e":"4845","980f8d5e":"4848","0c94c658":"4887","06322d53":"4972",d8746e52:"5000",bb43b8ce:"5006","3ee3a370":"5010","2a4d41ed":"5062","92dd0956":"5086","23f93eeb":"5120","16682cd3":"5138","46076c8b":"5169","017e736e":"5183",d0ba620f:"5334",aa1cf9a2:"5363","16815c2a":"5380",c34cc4c9:"5427","98306a23":"5535",d7a493e6:"5666","078a6308":"5732",c377a04b:"5742","9a1c8bc6":"5760","8be9dc67":"5773",a8d11699:"5834","488157d7":"6061","56ccfc32":"6098",c30ee527:"6204","8c7569e5":"6205",c5b25a7c:"6247",cf518063:"6251","2b265210":"6257","1c93e70c":"6276","15868c40":"6528",ba43b2d5:"6554","952dfacb":"6571","928a5d6f":"6576","1798d0b3":"6585","76bcd116":"6637","772fc39d":"6704",d077f377:"6738",e10f7c24:"6803","83b912d4":"6826",f7912ff8:"6834","02bfc02d":"6858","77cc432a":"6867","9c5158ac":"6926","89196f72":"6995","97081ee7":"7033","6c5232c2":"7135",c251e734:"7179","1cdac986":"7248",f1257df2:"7278","723607d1":"7297",f33f2c05:"7309",b3de9677:"7319","3cfbc8af":"7433",eceb3b9b:"7436",ec040517:"7458","814f3328":"7472","5df6e7df":"7514",f6ca3de5:"7532","4d9df5b1":"7540","107910e9":"7637",a6aa9e1f:"7643","104749c9":"7662",c5e834bc:"7700","7e0ce508":"7722",bfb64759:"7794",ca8fbf24:"7807","0ea64360":"7814",b57ca7d5:"7879","1e4e1fb6":"7889","9edb318c":"8032","234733fd":"8053","0b621d16":"8059","01a85c17":"8209",a470b55c:"8242","4aa001c0":"8317","6a35a4d8":"8439",e5f53749:"8465","5058a078":"8505","935f2afb":"8581",c97e0540:"8590",bac2c42d:"8604","8417e7a5":"8681","425cb3cb":"8707","1be78505":"8714",a7e6874c:"8738","26c0a43c":"8799","2c0d2b92":"8819","81f6aa2c":"9033","4a9d0f4c":"9040","7f479c52":"9070","86a1f821":"9186",f87e687e:"9251","7538b401":"9309","3245f64b":"9327","4be897c9":"9350","382b9f11":"9445",cba69ead:"9544","4add0c6c":"9564","3961e600":"9565","5eabd930":"9612","575d1ad6":"9700",ae967838:"9876","20e2ece2":"9957"}[e]||e,r.p+r.u(e)},(()=>{var e={5354:0,1869:0};r.f.j=(a,c)=>{var d=r.o(e,a)?e[a]:void 0;if(0!==d)if(d)c.push(d[2]);else if(/^(1869|5354)$/.test(a))e[a]=0;else{var f=new Promise(((c,f)=>d=e[a]=[c,f]));c.push(d[2]=f);var b=r.p+r.u(a),t=new Error;r.l(b,(c=>{if(r.o(e,a)&&(0!==(d=e[a])&&(e[a]=void 0),d)){var f=c&&("load"===c.type?"missing":c.type),b=c&&c.target&&c.target.src;t.message="Loading chunk "+a+" failed.\n("+f+": "+b+")",t.name="ChunkLoadError",t.type=f,t.request=b,d[1](t)}}),"chunk-"+a,a)}},r.O.j=a=>0===e[a];var a=(a,c)=>{var d,f,b=c[0],t=c[1],o=c[2],n=0;if(b.some((a=>0!==e[a]))){for(d in t)r.o(t,d)&&(r.m[d]=t[d]);if(o)var i=o(r)}for(a&&a(c);n<b.length;n++)f=b[n],r.o(e,f)&&e[f]&&e[f][0](),e[f]=0;return r.O(i)},c=self.webpackChunkdocs=self.webpackChunkdocs||[];c.forEach(a.bind(null,0)),c.push=a.bind(null,c.push.bind(c))})()})(); \ No newline at end of file diff --git a/docs/0.16.0/ast-builder/expressions/conditional/index.html b/docs/0.16.0/ast-builder/expressions/conditional/index.html new file mode 100644 index 00000000..3cc6e11b --- /dev/null +++ b/docs/0.16.0/ast-builder/expressions/conditional/index.html @@ -0,0 +1,17 @@ +<!doctype html> +<html lang="en" dir="ltr" class="docs-wrapper docs-doc-page docs-version-current plugin-docs plugin-id-default docs-doc-id-ast-builder/expressions/conditional" data-has-hydrated="false"> +<head> +<meta charset="UTF-8"> +<meta name="generator" content="Docusaurus v2.4.3"> +<title data-rh="true">Conditional | GlueSQL + + + + + +
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/ast-builder/expressions/nested/index.html b/docs/0.16.0/ast-builder/expressions/nested/index.html new file mode 100644 index 00000000..a15e83b2 --- /dev/null +++ b/docs/0.16.0/ast-builder/expressions/nested/index.html @@ -0,0 +1,17 @@ + + + + + +Nested | GlueSQL + + + + + + + + + + \ No newline at end of file diff --git a/docs/0.16.0/ast-builder/expressions/operator-based/index.html b/docs/0.16.0/ast-builder/expressions/operator-based/index.html new file mode 100644 index 00000000..f1233305 --- /dev/null +++ b/docs/0.16.0/ast-builder/expressions/operator-based/index.html @@ -0,0 +1,17 @@ + + + + + +Operator Based | GlueSQL + + + + + + + + + + \ No newline at end of file diff --git a/docs/0.16.0/ast-builder/expressions/pattern-matching/index.html b/docs/0.16.0/ast-builder/expressions/pattern-matching/index.html new file mode 100644 index 00000000..4fef224d --- /dev/null +++ b/docs/0.16.0/ast-builder/expressions/pattern-matching/index.html @@ -0,0 +1,17 @@ + + + + + +Pattern Matching | GlueSQL + + + + + +
+

Pattern Matching

Pattern matching is a crucial feature in SQL that allows you to match rows based on specific patterns in a column. GlueSQL provides 4 pattern matching operators: like, ilike, not_like, and not_ilike.

Here's how you can use these operators with two special characters:

  • %: Matches any number of characters, including zero characters
  • _: Matches exactly one character

LIKE Operator

The like operator is used in a WHERE clause to search for a specified pattern in a column.

Here is an example:

let actual = table("Category")
.select()
.filter(
col("name")
.like(text("D%"))
.or(col("name").like(text("M___"))),
)
.execute(glue)
.await;

In this example, the query will return all rows from the Category table where the name column starts with "D" or where the name is exactly four characters long and starts with "M".

ILIKE Operator

The ilike operator is used in a WHERE clause to search for a specified pattern in a column, regardless of case.

Here is an example:

let actual = table("Category")
.select()
.filter(
col("name")
.ilike(text("D%"))
.or(col("name").ilike(text("M___"))),
)
.execute(glue)
.await;

In this example, the query will return all rows from the Category table where the name column starts with "D" or "d", or where the name is exactly four characters long and starts with "M" or "m".

NOT_LIKE Operator

The not_like operator is used in a WHERE clause to match rows that don't follow the specific pattern.

Here is an example:

let actual = table("Category")
.select()
.filter(
col("name")
.not_like(text("D%"))
.and(col("name").not_like(text("M___"))),
)
.execute(glue)
.await;

In this example, the query will return all rows from the Category table where the name column does not start with "D" and the name is not exactly four characters long and does not start with "M".

NOT_ILIKE Operator

The not_ilike operator is used in a WHERE clause to match rows that don't follow the specific pattern, regardless of case.

Here is an example:

let actual = table("Category")
.select()
.filter(
col("name")
.not_ilike(text("D%"))
.and(col("name").not_ilike(text("M___"))),
)
.execute(glue)
.await;

In this example, the query will return all rows from the Category table where the name column does not start with "D" or "d", and the name is not exactly four characters long and does not start with "M" or "m".

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/ast-builder/expressions/value-checking/index.html b/docs/0.16.0/ast-builder/expressions/value-checking/index.html new file mode 100644 index 00000000..41fda600 --- /dev/null +++ b/docs/0.16.0/ast-builder/expressions/value-checking/index.html @@ -0,0 +1,17 @@ + + + + + +Value Checking | GlueSQL + + + + + + + + + + \ No newline at end of file diff --git a/docs/0.16.0/ast-builder/functions/date-&-time/conversion/index.html b/docs/0.16.0/ast-builder/functions/date-&-time/conversion/index.html new file mode 100644 index 00000000..b9f221c1 --- /dev/null +++ b/docs/0.16.0/ast-builder/functions/date-&-time/conversion/index.html @@ -0,0 +1,17 @@ + + + + + +Conversion | GlueSQL + + + + + +
+

Conversion

GlueSQL provides date and time conversion functions that allow you to convert text data to datetime data types such as Date, Time, and Timestamp. These functions are to_date, to_time, and to_timestamp.

For this tutorial, we assume there's a table named Visitor with various columns including visit_date, visit_time, and visit_time_stamp which are of TEXT type.

Date Conversion - to_date

The to_date function converts a text string to a date.

There are two ways to call the to_date function in GlueSQL:

let actual = table("Visitor")
.select()
.project("id")
.project("name")
.project(col("visit_date").to_date("'%Y-%m-%d'")) // Method 1: Calling the to_date method on a column
.project(to_date("visit_date", "'%Y-%m-%d'")) // Method 2: Using the to_date function directly
.execute(glue)
.await;

Time Conversion - to_time

The to_time function converts a text string to a time.

There are two ways to call the to_time function in GlueSQL:

let actual = table("Visitor")
.select()
.project("id")
.project("name")
.project(col("visit_time").to_time("'%H:%M:%S'")) // Method 1: Calling the to_time method on a column
.project(to_time("visit_time", "'%H:%M:%S'")) // Method 2: Using the to_time function directly
.execute(glue)
.await;

Timestamp Conversion - to_timestamp

The to_timestamp function converts a text string to a timestamp.

There are two ways to call the to_timestamp function in GlueSQL:

let actual = table("Visitor")
.select()
.project("id")
.project("name")
.project(col("visit_time_stamp").to_timestamp("'%Y-%m-%d %H:%M:%S'")) // Method 1: Calling the to_timestamp method on a column
.project(to_timestamp("visit_time_stamp", "'%Y-%m-%d %H:%M:%S'")) // Method 2: Using the to_timestamp function directly
.execute(glue)
.await;
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/ast-builder/functions/date-&-time/current-date-and-time/index.html b/docs/0.16.0/ast-builder/functions/date-&-time/current-date-and-time/index.html new file mode 100644 index 00000000..175448b2 --- /dev/null +++ b/docs/0.16.0/ast-builder/functions/date-&-time/current-date-and-time/index.html @@ -0,0 +1,17 @@ + + + + + +Current Date and Time | GlueSQL + + + + + +
+

Current Date and Time

GlueSQL provides a function to get the current date and time: now.

Now - now

The now function returns the current date and time.

let actual = table("Record")
.select()
.filter(col("time_stamp").gt(now())) // select rows where "time_stamp" is later than current time
.project("id, time_stamp")
.execute(glue)
.await;

In the above example, the filter method uses now to select rows where the "time_stamp" column is later than the current time.

When inserting data into a table, you can use the now function to record the current time:

let actual = table("Record")
.insert()
.values(vec![
"1, '2022-12-23T05:30:11.164932863'",
"2, NOW()", // Inserts the current time
"3, '9999-12-31T23:59:40.364832862'",
])
.execute(glue)
.await;

In the example above, the "time_stamp" column for the row with id 2 is set to the current time at the moment of insertion.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/ast-builder/functions/date-&-time/date-and-time-extraction/index.html b/docs/0.16.0/ast-builder/functions/date-&-time/date-and-time-extraction/index.html new file mode 100644 index 00000000..1fb3f261 --- /dev/null +++ b/docs/0.16.0/ast-builder/functions/date-&-time/date-and-time-extraction/index.html @@ -0,0 +1,17 @@ + + + + + +Date and Time Extraction | GlueSQL + + + + + + + + + + \ No newline at end of file diff --git a/docs/0.16.0/ast-builder/functions/date-&-time/formatting/index.html b/docs/0.16.0/ast-builder/functions/date-&-time/formatting/index.html new file mode 100644 index 00000000..2c2371d0 --- /dev/null +++ b/docs/0.16.0/ast-builder/functions/date-&-time/formatting/index.html @@ -0,0 +1,17 @@ + + + + + +Formatting | GlueSQL + + + + + +
+

Formatting

In GlueSQL, you can format date, time, and timestamp values to a specific format using the format function.

For this tutorial, we assume there's a table named Visitor with columns id, name, visit_date, visit_time, and visit_timestamp.

Formatting Date

The format function can be used to change the format of a date.

let actual = table("Visitor")
.select()
.project("name")
.project("visit_date")
.project(col("visit_date").format(text("%Y-%m"))) // Formats the visit_date to the year-month format
.project(format(col("visit_date"), text("%m"))) // Formats the visit_date to the month format
.execute(glue)
.await;

Formatting Time

The format function can also be used to change the format of a time.

let actual = table("Visitor")
.select()
.project("name")
.project("visit_time")
.project(col("visit_time").format(text("%H:%M:%S"))) // Formats the visit_time to the hour-minute-second format
.project(format(col("visit_time"), text("%M:%S"))) // Formats the visit_time to the minute-second format
.execute(glue)
.await;

Formatting Timestamp

The format function can be used to change the format of a timestamp.

let actual = table("Visitor")
.select()
.project("name")
.project("visit_timestamp")
.project(col("visit_timestamp").format(text("%Y-%m-%d %H:%M:%S"))) // Formats the visit_timestamp to the year-month-date hour-minute-second format
.project(format(col("visit_timestamp"), text("%Y-%m-%d %H:%M:%S"))) // Formats the visit_timestamp to the year-month-date hour-minute-second format
.execute(glue)
.await;
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/ast-builder/functions/geometry/coordinate-extraction/index.html b/docs/0.16.0/ast-builder/functions/geometry/coordinate-extraction/index.html new file mode 100644 index 00000000..40087d01 --- /dev/null +++ b/docs/0.16.0/ast-builder/functions/geometry/coordinate-extraction/index.html @@ -0,0 +1,17 @@ + + + + + +Coordinate Extraction | GlueSQL + + + + + + + + + + \ No newline at end of file diff --git a/docs/0.16.0/ast-builder/functions/geometry/distance-calculation/index.html b/docs/0.16.0/ast-builder/functions/geometry/distance-calculation/index.html new file mode 100644 index 00000000..f467c871 --- /dev/null +++ b/docs/0.16.0/ast-builder/functions/geometry/distance-calculation/index.html @@ -0,0 +1,17 @@ + + + + + +Distance Calculation | GlueSQL + + + + + + + + + + \ No newline at end of file diff --git a/docs/0.16.0/ast-builder/functions/geometry/point-creation/index.html b/docs/0.16.0/ast-builder/functions/geometry/point-creation/index.html new file mode 100644 index 00000000..e416fbbf --- /dev/null +++ b/docs/0.16.0/ast-builder/functions/geometry/point-creation/index.html @@ -0,0 +1,17 @@ + + + + + +Point Creation | GlueSQL + + + + + + + + + + \ No newline at end of file diff --git a/docs/0.16.0/ast-builder/functions/list-&-map/list-and-map-concatenation/index.html b/docs/0.16.0/ast-builder/functions/list-&-map/list-and-map-concatenation/index.html new file mode 100644 index 00000000..98a4f97f --- /dev/null +++ b/docs/0.16.0/ast-builder/functions/list-&-map/list-and-map-concatenation/index.html @@ -0,0 +1,17 @@ + + + + + +List and Map Concatenation | GlueSQL + + + + + + + + + + \ No newline at end of file diff --git a/docs/0.16.0/ast-builder/functions/list-&-map/list-manipulation/index.html b/docs/0.16.0/ast-builder/functions/list-&-map/list-manipulation/index.html new file mode 100644 index 00000000..d059e321 --- /dev/null +++ b/docs/0.16.0/ast-builder/functions/list-&-map/list-manipulation/index.html @@ -0,0 +1,17 @@ + + + + + +List Manipulation | GlueSQL + + + + + + + + + + \ No newline at end of file diff --git a/docs/0.16.0/ast-builder/functions/math/basic-arithmetic/index.html b/docs/0.16.0/ast-builder/functions/math/basic-arithmetic/index.html new file mode 100644 index 00000000..cceec363 --- /dev/null +++ b/docs/0.16.0/ast-builder/functions/math/basic-arithmetic/index.html @@ -0,0 +1,17 @@ + + + + + +Basic Arithmetic | GlueSQL + + + + + +
+

Basic Arithmetic

GlueSQL provides a number of basic arithmetic operations such as absolute value (abs), division (divide), modulo (modulo), greatest common divisor (gcd), and least common multiple (lcm).

For this tutorial, we assume there's a table named Number with columns id and number.

Absolute Value - ABS

The abs function returns the absolute value of a number.

let actual = values(vec!["0, 0", "1, -3", "2, 4", "3, -29"])
.alias_as("number")
.select()
.project("column1")
.project(abs("column2")) // Takes the absolute value of column2
.project(col("column2").abs()) // Takes the absolute value of column2
.execute(glue)
.await;

Division - DIV

The divide function divides one number by another.

let actual = table("Number")
.select()
.project("id")
.project(divide("number", 3)) // Divides the number by 3
.project(divide(col("number"), 3)) // Divides the number by 3
.execute(glue)
.await;

Modulo - MOD

The modulo function returns the remainder of one number divided by another.

let actual = table("Number")
.select()
.project("id")
.project(modulo("number", 4)) // Gets the remainder of number divided by 4
.project(modulo(col("number"), 4)) // Gets the remainder of number divided by 4
.execute(glue)
.await;

Greatest Common Divisor - GCD

The gcd function returns the greatest common divisor of two numbers.

let actual = table("Number")
.select()
.project("id")
.project(gcd("number", 12)) // Gets the GCD of number and 12
.project(gcd(col("number"), 12)) // Gets the GCD of number and 12
.execute(glue)
.await;

Least Common Multiple - LCM

The lcm function returns the least common multiple of two numbers.

let actual = table("Number")
.select()
.project("id")
.project(lcm("number", 3)) // Gets the LCM of number and 3
.project(lcm(col("number"), 3)) // Gets the LCM of number and 3
.execute(glue)
.await;
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/ast-builder/functions/math/conversion/index.html b/docs/0.16.0/ast-builder/functions/math/conversion/index.html new file mode 100644 index 00000000..5f01b047 --- /dev/null +++ b/docs/0.16.0/ast-builder/functions/math/conversion/index.html @@ -0,0 +1,17 @@ + + + + + +Conversion | GlueSQL + + + + + +
+

Conversion

The AST (Abstract Syntax Tree) Builder in GlueSQL provides mathematical conversion functions like degrees and radians. These functions convert angles expressed in radians to degrees and vice versa.

For the sake of this tutorial, we'll assume there's a table named Number with columns input (of type INTEGER) and number (of type FLOAT).

Degrees Function

The degrees function converts an angle from radians to degrees.

You can call this function in two ways in GlueSQL:

let actual = table("Number")
.select()
.project("input")
.project(degrees("number")) // Method 1: Using the degrees function directly
.project(col("number").degrees()) // Method 2: Calling the degrees method on a column
.execute(glue)
.await;

Radians Function

The radians function converts an angle from degrees to radians.

Just like with the degrees function, there are two ways to call this function:

let actual = table("Number")
.select()
.project("input")
.project(radians("number")) // Method 1: Using the radians function directly
.project(col("number").radians()) // Method 2: Calling the radians method on a column
.execute(glue)
.await;
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/ast-builder/functions/math/logarithmic-and-exponential/index.html b/docs/0.16.0/ast-builder/functions/math/logarithmic-and-exponential/index.html new file mode 100644 index 00000000..0e7ebf26 --- /dev/null +++ b/docs/0.16.0/ast-builder/functions/math/logarithmic-and-exponential/index.html @@ -0,0 +1,17 @@ + + + + + +Logarithmic and Exponential | GlueSQL + + + + + +
+

Logarithmic and Exponential

Todo

- EXP: Returns e raised to the power of a specified number.
- LN: Returns the natural logarithm of a number.
- LOG: Returns the logarithm of a number to a specified base.
- LOG10: Returns the base-10 logarithm of a number.
- LOG2: Returns the base-2 logarithm of a number.
- POWER: Raises a number to the power of another number.
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/ast-builder/functions/math/rounding/index.html b/docs/0.16.0/ast-builder/functions/math/rounding/index.html new file mode 100644 index 00000000..bcf04e75 --- /dev/null +++ b/docs/0.16.0/ast-builder/functions/math/rounding/index.html @@ -0,0 +1,17 @@ + + + + + +Rounding | GlueSQL + + + + + +
+

Rounding

The AST (Abstract Syntax Tree) Builder in GlueSQL provides several mathematical functions, including round, ceil, and floor. These functions are used to perform rounding operations on floating-point numbers.

For the sake of this tutorial, we'll assume there's a table named Number with columns id (of type INTEGER) and number (of type FLOAT).

Ceil Function

The ceil function rounds up the number to the nearest integer value that is greater than or equal to number.

In GlueSQL, you can call this function in two ways. Both methods are shown below:

let actual = table("Number")
.select()
.project("id")
.project(ceil("number")) // Method 1: Using the ceil function directly
.project(col("number").ceil()) // Method 2: Calling the ceil method on a column
.execute(glue)
.await;

Floor Function

The floor function rounds down the number to the nearest integer value that is less than or equal to number.

Again, there are two ways to call this function in GlueSQL:

let actual = table("Number")
.select()
.project("id")
.project(floor("number")) // Method 1: Using the floor function directly
.project(col("number").floor()) // Method 2: Calling the floor method on a column
.execute(glue)
.await;

Round Function

The round function rounds the number to the nearest integer. If number is halfway between two integers, it rounds towards the nearest even number.

The round function can also be called in two ways, as demonstrated below:

let actual = table("Number")
.select()
.project("id")
.project(round("number")) // Method 1: Using the round function directly
.project(col("number").round()) // Method 2: Calling the round method on a column
.execute(glue)
.await;
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/ast-builder/functions/math/special-mathematical/index.html b/docs/0.16.0/ast-builder/functions/math/special-mathematical/index.html new file mode 100644 index 00000000..64086955 --- /dev/null +++ b/docs/0.16.0/ast-builder/functions/math/special-mathematical/index.html @@ -0,0 +1,17 @@ + + + + + +Special Mathematical | GlueSQL + + + + + + + + + + \ No newline at end of file diff --git a/docs/0.16.0/ast-builder/functions/math/trigonometric/index.html b/docs/0.16.0/ast-builder/functions/math/trigonometric/index.html new file mode 100644 index 00000000..d0d8a343 --- /dev/null +++ b/docs/0.16.0/ast-builder/functions/math/trigonometric/index.html @@ -0,0 +1,17 @@ + + + + + +Trigonometric | GlueSQL + + + + + + + + + + \ No newline at end of file diff --git a/docs/0.16.0/ast-builder/functions/others/null-handling/index.html b/docs/0.16.0/ast-builder/functions/others/null-handling/index.html new file mode 100644 index 00000000..4a12f2c1 --- /dev/null +++ b/docs/0.16.0/ast-builder/functions/others/null-handling/index.html @@ -0,0 +1,17 @@ + + + + + +Null Handling | GlueSQL + + + + + +
+

Null Handling

In some cases, you may need to handle NULL values in your database. GlueSQL provides a function called ifnull to handle these cases.

IFNULL - ifnull

The ifnull function checks if the first expression is NULL, and if it is, it returns the value of the second expression. If the first expression is not NULL, it returns the value of the first expression.

let actual = table("Foo")
.select()
.project("id")
.project(col("name").ifnull(text("isnull"))) // If the "name" column is NULL, replace it with "isnull"
.execute(glue)
.await;

In the above example, if the "name" column is NULL, "isnull" is returned. Otherwise, the value of the "name" column is returned.

You can also use ifnull with another column:

let actual = table("Foo")
.select()
.project("id")
.project(col("name").ifnull(col("nickname"))) // If the "name" column is NULL, replace it with the value from the "nickname" column
.execute(glue)
.await;

In this example, if the "name" column is NULL, the value from the "nickname" column is returned. If "name" is not NULL, the value of the "name" column is returned.

The ifnull function can also be used without a table:

let actual = values(vec![
vec![ast_builder::ifnull(text("HELLO"), text("WORLD"))], // If "HELLO" is NULL (it's not), return "WORLD". Otherwise, return "HELLO".
vec![ast_builder::ifnull(null(), text("WORLD"))], // If NULL is NULL (it is), return "WORLD".
])
.execute(glue)
.await;

In the first case, "HELLO" is returned because it's not NULL. In the second case, "WORLD" is returned because the first value is NULL.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/ast-builder/functions/others/type-conversion/index.html b/docs/0.16.0/ast-builder/functions/others/type-conversion/index.html new file mode 100644 index 00000000..8fa2af95 --- /dev/null +++ b/docs/0.16.0/ast-builder/functions/others/type-conversion/index.html @@ -0,0 +1,17 @@ + + + + + +Type Conversion | GlueSQL + + + + + + + + + + \ No newline at end of file diff --git a/docs/0.16.0/ast-builder/functions/others/unique-identifier/index.html b/docs/0.16.0/ast-builder/functions/others/unique-identifier/index.html new file mode 100644 index 00000000..bd245f4e --- /dev/null +++ b/docs/0.16.0/ast-builder/functions/others/unique-identifier/index.html @@ -0,0 +1,17 @@ + + + + + +Unique Identifier | GlueSQL + + + + + + + + + + \ No newline at end of file diff --git a/docs/0.16.0/ast-builder/functions/text/case-conversion/index.html b/docs/0.16.0/ast-builder/functions/text/case-conversion/index.html new file mode 100644 index 00000000..3be0e204 --- /dev/null +++ b/docs/0.16.0/ast-builder/functions/text/case-conversion/index.html @@ -0,0 +1,17 @@ + + + + + +Case Conversion | GlueSQL + + + + + +
+

Case Conversion

GlueSQL provides several text case conversion functions that allow you to convert text data to upper case, lower case or capitalize each word in a string.

For this tutorial, we assume there's a table named Item with various columns including name, opt_name, and capped_name which are of TEXT type.

Upper Case Conversion - upper

The upper function converts a text string to upper case.

let actual = table("Item")
.select()
.project(col("name").upper()) // Convert the 'name' column to upper case
.execute(glue)
.await;

Lower Case Conversion - lower

The lower function converts a text string to lower case.

let actual = table("Item")
.select()
.project(col("name").lower()) // Convert the 'name' column to lower case
.execute(glue)
.await;

You can also filter the records based on the lower case conversion:

let actual = table("Item")
.select()
.filter(col("name").lower().eq("'abcd'")) // Filter records where lower case of 'name' is 'abcd'
.project("name")
.project(lower("name"))
.execute(glue)
.await;

Initial Capital Case Conversion - initcap

The initcap function converts a text string to initial capital case, i.e., it capitalizes the first character of each word in the string.

let actual = table("Item")
.select()
.project(col("capped_name").initcap()) // Convert the 'capped_name' column to initial capital case
.execute(glue)
.await;

You can also filter the records based on the initial capital case conversion:

let actual = table("Item")
.select()
.filter(col("capped_name").initcap().eq("'H/I Jk'")) // Filter records where initial capital case of 'capped_name' is 'H/I Jk'
.project("capped_name")
.execute(glue)
.await;
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/ast-builder/functions/text/character-conversion/index.html b/docs/0.16.0/ast-builder/functions/text/character-conversion/index.html new file mode 100644 index 00000000..e0f1a380 --- /dev/null +++ b/docs/0.16.0/ast-builder/functions/text/character-conversion/index.html @@ -0,0 +1,17 @@ + + + + + +Character Conversion | GlueSQL + + + + + +
+

Character Conversion

The AST Builder API in GlueSQL allows you to execute ascii and chr functions for character conversion.

ascii

ascii returns the ASCII value for the specific character.

ascii<'a, T: Into<ExprNode<'a>>>(expr: T) -> ExprNode<'a>

chr

chr returns the character based on the ASCII code.

chr<'a, T: Into<ExprNode<'a>>>(expr: T) -> ExprNode<'a>

Examples

In these examples, the ASCII and CHR functions should return matching values.

use {
gluesql_core::{ast_builder::{function as f, *}}
};

values(vec![
vec![f::ascii("'\t'"), f::chr(9)],
vec![f::ascii("'\n'"), f::chr(10)],
vec![f::ascii("'\r'"), f::chr(13)],
vec![f::ascii("' '"), f::chr(32)],
vec![f::ascii("'!'"), f::chr(33)],
vec![f::ascii("'\"'"), f::chr(34)],
vec![f::ascii("'#'"), f::chr(35)],
vec![f::ascii("'$'"), f::chr(36)],
vec![f::ascii("'%'"), f::chr(37)],
vec![f::ascii("'&'"), f::chr(38)],
vec![f::ascii("''''"), f::chr(39)],
vec![f::ascii("','"), f::chr(44)],
])
.alias_as("Sub")
.select()
.project("column1 AS ascii")
.project("column2 AS char")
.execute(glue)
.await;
asciichar
9\t
10\n
13\r
32" "
33!
34"
35#
36$
37%
38&
39'
44,
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/ast-builder/functions/text/padding/index.html b/docs/0.16.0/ast-builder/functions/text/padding/index.html new file mode 100644 index 00000000..aded20c5 --- /dev/null +++ b/docs/0.16.0/ast-builder/functions/text/padding/index.html @@ -0,0 +1,17 @@ + + + + + +Padding | GlueSQL + + + + + +
+

Padding

The AST Builder API in GlueSQL allows you to execute lpad and rpad functions for text padding.

lpad

lpad returns the string with leading space if the length of the string is less than the specified length.

lpad<'a, T: Into<ExprNode<'a>>>(expr: T, len: usize, fill: Option<String>) -> ExprNode<'a>

rpad

rpad returns the string with trailing space if the length of the string is less than the specified length.

rpad<'a, T: Into<ExprNode<'a>>>(expr: T, len: usize, fill: Option<String>) -> ExprNode<'a>

Examples

In these examples, the LPAD and RPAD functions should return matching values.

use {
crate::*,
gluesql_core::{
ast_builder::{function as f, *},
prelude::Value::{Null, Str},
},
};

test_case!(padding, {
let glue = get_glue!();

let actual = values(vec![
vec![f::lpad("'hello'", 10, None), f::rpad("'hello'", 10, None)],
vec![
f::lpad("'hello'", 10, Some("'ab'".into())),
f::rpad("'hello'", 10, Some("'ab'".into())),
],
vec![f::lpad("'hello'", 3, None), f::rpad("'hello'", 3, None)],
vec![
f::lpad("'hello'", 3, Some("'ab'".into())),
f::rpad("'hello'", 3, Some("'ab'".into())),
],
vec![f::lpad("NULL", 5, None), f::rpad("NULL", 5, None)],
])
.alias_as("Sub")
.select()
.project("column1 AS lpaded")
.project("column2 AS rpaded")
.execute(glue)
.await;
let expected = Ok(select_with_null!(
lpaded | rpaded;
Str(" hello".to_owned()) Str("hello ".to_owned());
Str("ababahello".to_owned()) Str("helloababa".to_owned());
Str("hel".to_owned()) Str("hel".to_owned());
Str("hel".to_owned()) Str("hel".to_owned());
Null Null
));
assert_eq!(
actual, expected,
"lpad and rpad should pad the string with given length"
);
});
| lpaded       | rpaded       |
| ------------ | ------------ |
| ' hello' | 'hello ' |
| 'ababahello' | 'helloababa' |
| 'hel' | 'hel' |
| 'hel' | 'hel' |
| Null | Null |
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/ast-builder/functions/text/position-and-indexing/index.html b/docs/0.16.0/ast-builder/functions/text/position-and-indexing/index.html new file mode 100644 index 00000000..0f0623b9 --- /dev/null +++ b/docs/0.16.0/ast-builder/functions/text/position-and-indexing/index.html @@ -0,0 +1,17 @@ + + + + + +Position and Indexing | GlueSQL + + + + + +
+

Position and Indexing

GlueSQL provides several functions for text manipulation, including finding the index of a substring (find_idx), finding the position of a substring (position), and getting the leftmost or rightmost characters (left and right).

Find Index - find_idx

find_idx function returns the first position of the specified substring, starting from the beginning of the string or the specified position.

let test_num = find_idx(text("strawberry"), text("berry"), None);  // Returns 6
let test_num = find_idx(text("Oracle Database 12c Release"), text("as"), Some(num(15))); // Returns 25

You can also call find_idx directly on a string:

let test_num = text("Oracle Database 12c Release").find_idx(text("as"), Some(num(15)));  // Returns 25

Position - position

The position function is similar to find_idx, but it starts counting from 1 and does not take a third argument for the starting position.

let test_num = position(text("cake"), text("ke"));  // Returns 3

Left - left

The left function returns the leftmost characters of a string. The second argument specifies the number of characters to return.

let test_str = left(text("Hello, World"), num(7));  // Returns "Hello, "

Right - right

The right function returns the rightmost characters of a string. The second argument specifies the number of characters to return.

let test_str = right(text("Hello, World"), num(7));  // Returns ", World"
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/ast-builder/functions/text/text-manipulation/index.html b/docs/0.16.0/ast-builder/functions/text/text-manipulation/index.html new file mode 100644 index 00000000..68cc74e7 --- /dev/null +++ b/docs/0.16.0/ast-builder/functions/text/text-manipulation/index.html @@ -0,0 +1,17 @@ + + + + + +Text Manipulation | GlueSQL + + + + + +
+

Text Manipulation

Todo

- CONCAT: Concatenates two or more strings into one.
- CONCAT_WS: Concatenates two or more strings into one with a separator.
- SUBSTR: Returns a part of a string.
- REPEAT: Repeats a string a specified number of times.
- REVERSE: Reverses the order of the characters in a string.
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/ast-builder/functions/text/trimming/index.html b/docs/0.16.0/ast-builder/functions/text/trimming/index.html new file mode 100644 index 00000000..386e4963 --- /dev/null +++ b/docs/0.16.0/ast-builder/functions/text/trimming/index.html @@ -0,0 +1,17 @@ + + + + + +Trimming | GlueSQL + + + + + +
+

Trimming

GlueSQL provides several text trimming functions that allow you to remove leading or trailing characters from a text string.

For this tutorial, we assume there's a table named Food with an id column of INTEGER type and a name column of TEXT type.

Right Trimming - rtrim

The rtrim function removes trailing characters from a text string. You can specify the characters to be removed as an argument to the function. If no argument is provided, it trims spaces by default.

// Trims trailing spaces from "chicken   "
let test_text = text("chicken ").rtrim(Some(text(" ")));

let actual = table("Food")
.insert()
.columns("id, name")
.values(vec![vec![num(1), test_text]])
.execute(glue)
.await;

Left Trimming - ltrim

The ltrim function removes leading characters from a text string. You can specify the characters to be removed as an argument to the function. If no argument is provided, it trims spaces by default.

// Trims leading spaces from "   chicken"
let test_text = ltrim(text(" chicken"), Some(text(" ")));

let actual = table("Food")
.insert()
.columns("id, name")
.values(vec![vec![num(2), test_text]])
.execute(glue)
.await;

Right and Left Trimming

You can combine rtrim and ltrim to trim both sides of a string:

// Trims leading "ch" and trailing spaces from "chicken"
let test_text = text("chicken").ltrim(Some(text("ch"))).rtrim(None);

let actual = table("Food")
.insert()
.columns("id, name")
.values(vec![vec![num(3), test_text]])
.execute(glue)
.await;
// Trims trailing "en" and leading spaces from "chicken"
let test_text = text("chicken").rtrim(Some(text("en"))).ltrim(None);

let actual = table("Food")
.insert()
.columns("id, name")
.values(vec![vec![num(4), test_text]])
.execute(glue)
.await;
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/ast-builder/intro/index.html b/docs/0.16.0/ast-builder/intro/index.html new file mode 100644 index 00000000..3146de96 --- /dev/null +++ b/docs/0.16.0/ast-builder/intro/index.html @@ -0,0 +1,17 @@ + + + + + +Introduction | GlueSQL + + + + + +
+

AST Builder

GlueSQL offers two ways to create and execute queries: using SQL statements or using the AST Builder. In this introductory page, we will focus on the AST Builder.

When executing SQL statements in GlueSQL, they need to be converted into an internal AST (Abstract Syntax Tree) format. The AST Builder allows users to directly create and manipulate ASTs, making it more efficient and flexible compared to traditional SQL statements.

The AST Builder has some similarities to ORM (Object Relational Mapping) query builders, but there are several key differences:

  • ORM query builders often support multiple databases, which can limit their features to a subset of each database's capabilities. However, the AST Builder is designed exclusively for GlueSQL, allowing it to take full advantage of all GlueSQL features.
  • The AST Builder is flexible in terms of input, accepting both its own API calls and SQL expressions.
  • ORM query builders typically generate SQL statements, which must then be executed by the database. This introduces overhead. In contrast, the GlueSQL AST Builder directly generates executable ASTs, making it highly efficient.
  • The AST Builder supports features that are not available with SQL, such as allowing users to directly specify the internal execution strategy. This is similar to SQL query hints, but with the AST Builder, the user's instructions are executed precisely, rather than being treated as suggestions.

Currently, the AST Builder only supports Rust language interfaces, but support for other languages, such as JavaScript, is planned for future releases.

Below are some sample code snippets using the GlueSQL AST Builder in Rust, categorized by query type:

CREATE TABLE

let actual = table("Foo")
.create_table()
.add_column("id INTEGER")
.add_column("name TEXT")
.execute(glue)
.await;

INSERT

let actual = table("Foo")
.insert()
.columns("id, name")
.values(vec![
vec![num(100), text("Pickle")],
vec![num(200), text("Lemon")],
])
.execute(glue)
.await;

SELECT

let actual = table("Foo")
.select()
.project("id, name")
.execute(glue)
.await;

UPDATE

let actual = table("Foo")
.update()
.set("id", col("id").mul(2))
.filter(col("id").eq(200))
.execute(glue)
.await;

SELECT with filtering

let actual = table("Foo")
.select()
.filter("name = 'Lemon'")
.project("id, name")
.build()
.expect("build and execute")
.execute(glue)
.await;

DELETE

let actual = table("Foo")
.delete()
.filter(col("id").gt(200))
.execute(glue)
.await;

Summary

In this introduction to the AST Builder, we have covered the key differences between the AST Builder and ORM query builders, and provided examples of how to use the AST Builder in Rust for various query types. The AST Builder is a powerful and efficient tool for working with GlueSQL, offering greater flexibility and control compared to traditional SQL statements.

Remember that the AST Builder currently supports only Rust language interfaces, but support for other languages, such as JavaScript, is planned for future releases.

By leveraging the AST Builder, you can take full advantage of GlueSQL's features, and build more efficient and flexible database applications.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/ast-builder/statements/data-manipulation/deleting-data/index.html b/docs/0.16.0/ast-builder/statements/data-manipulation/deleting-data/index.html new file mode 100644 index 00000000..cfa02544 --- /dev/null +++ b/docs/0.16.0/ast-builder/statements/data-manipulation/deleting-data/index.html @@ -0,0 +1,17 @@ + + + + + +Deleting Data | GlueSQL + + + + + +
+

Deleting Data

In this section, we will discuss how to delete data from a table using GlueSQL.

Delete with Filter

To delete specific rows from a table, you can use the delete method on a table object, followed by the filter method to provide a condition that the rows must meet. You can then use the execute method to apply the changes.

let actual = table("Foo")
.delete()
.filter(col("flag").eq(false))
.execute(glue)
.await;
let expected = Ok(Payload::Delete(1));
test(actual, expected);

This code deletes the rows in the table Foo where the flag column value is false.

Delete All Rows

To delete all rows from a table, you can use the delete method on a table object, followed by the execute method.

let actual = table("Foo").delete().execute(glue).await;
let expected = Ok(Payload::Delete(2));
test(actual, expected);

This code deletes all rows from the table Foo.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/ast-builder/statements/data-manipulation/inserting-data/index.html b/docs/0.16.0/ast-builder/statements/data-manipulation/inserting-data/index.html new file mode 100644 index 00000000..372c60f7 --- /dev/null +++ b/docs/0.16.0/ast-builder/statements/data-manipulation/inserting-data/index.html @@ -0,0 +1,17 @@ + + + + + +Inserting Data | GlueSQL + + + + + +
+

Inserting Data

In this section, we will discuss how to insert data into a table using GlueSQL.

Basic Insert

To insert data into a table, you can use the insert method on a table object. You can then use the values method to provide the values you want to insert.

let actual = table("Foo")
.insert()
.values(vec!["1, 'Fruit', 0.1", "2, 'Meat', 0.8"])
.execute(glue)
.await;
let expected = Ok(Payload::Insert(2));
test(actual, expected);

This code inserts two rows into the table Foo. The first row has the values 1, 'Fruit', 0.1 and the second row has the values 2, 'Meat', 0.8.

Insert with Specified Columns

If you want to specify the columns to insert data into, you can use the columns method followed by the values method. The values method should contain the data for the specified columns.

let actual = table("Foo")
.insert()
.columns("id, name")
.values(vec![vec![num(3), text("Drink")]])
.execute(glue)
.await;
let expected = Ok(Payload::Insert(1));
test(actual, expected);

This code inserts a new row into the table Foo with the specified columns id and name. The rate column is not specified, so it will be set to its default value.

Insert from Source

You can also insert data into a table using a SELECT statement as the source. To do this, use the as_select method followed by the execute method.

let actual = table("Bar")
.insert()
.as_select(table("Foo").select().project("id, name"))
.execute(glue)
.await;
let expected = Ok(Payload::Insert(3));
test(actual, expected);

This code inserts data into the table Bar using the SELECT statement on the table Foo. The project method is used to specify the columns id and name as the source data.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/ast-builder/statements/data-manipulation/updating-data/index.html b/docs/0.16.0/ast-builder/statements/data-manipulation/updating-data/index.html new file mode 100644 index 00000000..e025a25f --- /dev/null +++ b/docs/0.16.0/ast-builder/statements/data-manipulation/updating-data/index.html @@ -0,0 +1,17 @@ + + + + + +Updating Data | GlueSQL + + + + + +
+

Updating Data

In this section, we will discuss how to update data in a table using GlueSQL.

Basic Update

To update data in a table, you can use the update method on a table object, followed by the set method to specify the column and the new value. You can then use the execute method to apply the changes.

let actual = table("Foo")
.update()
.set("score", col("score").div(10))
.execute(glue)
.await;
let expected = Ok(Payload::Update(3));
test(actual, expected);

This code updates all rows in the table Foo, dividing the score column value by 10.

Update with Multiple Columns

To update multiple columns, you can chain multiple set methods with the desired column names and new values.

let actual = table("Foo")
.update()
.set("score", "score * 2 + 5")
.set("flag", col("flag").negate())
.execute(glue)
.await;
let expected = Ok(Payload::Update(3));
test(actual, expected);

This code updates all rows in the table Foo, applying the following changes:

  1. The score column value is multiplied by 2 and 5 is added.
  2. The flag column value is negated (i.e., true becomes false and false becomes true).

Update with Filter

If you want to update only specific rows, you can use the filter method to provide a condition that the rows must meet.

let actual = table("Foo")
.update()
.set("score", "score * 2 + 5")
.set("flag", col("flag").negate())
.filter(col("score").lte(30))
.execute(glue)
.await;
let expected = Ok(Payload::Update(2));
test(actual, expected);

This code updates the rows in the table Foo where the score column value is less than or equal to 30. The score and flag column values are updated as described in the previous example.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/ast-builder/statements/querying/creating-derived-subqueries/index.html b/docs/0.16.0/ast-builder/statements/querying/creating-derived-subqueries/index.html new file mode 100644 index 00000000..624187a0 --- /dev/null +++ b/docs/0.16.0/ast-builder/statements/querying/creating-derived-subqueries/index.html @@ -0,0 +1,17 @@ + + + + + +Creating Derived Subqueries | GlueSQL + + + + + +
+

Creating Derived Subqueries

This document covers the alias_as functionality of the AST Builder in the GlueSQL project. The alias_as method allows you to create a derived subquery, which is similar to subqueries in SQL. It gives you the ability to use the output of a query as a table to perform further queries.

Basic Usage

To use the alias_as method, simply chain it to the end of a query builder method before executing the query. The derived subquery can then be used for further queries. Here's an example:

let actual = table("Item")
.select()
.alias_as("Sub")
.select()
.execute(glue)
.await;

In this example, the alias_as method is used after the select method, creating a derived subquery named "Sub" that can be used in subsequent queries.

Examples

The following examples demonstrate how to use the alias_as method with various query operations.

Derived Subquery with Filter

let actual = table("Item")
.select()
.filter("item_id = 300")
.alias_as("Sub")
.select()
.execute(glue)
.await;

Derived Subquery with Projection

let actual = table("Item")
.select()
.project("item_id")
.alias_as("Sub")
.select()
.execute(glue)
.await;

Derived Subquery with Join

let actual = table("Item")
.alias_as("i")
.select()
.join_as("Category", "c")
.on("c.category_id = i.category_id")
.alias_as("Sub")
.select()
.project("item_name")
.project("category_name")
.execute(glue)
.await;

Derived Subquery with Group By and Having

let actual = table("Category")
.select()
.project("category_name")
.alias_as("Sub1")
.select()
.group_by("category_name")
.having("category_name = 'Meat'")
.alias_as("Sub2")
.select()
.execute(glue)
.await;

Derived Subquery with Order By

let actual = table("Item")
.select()
.order_by("price DESC")
.alias_as("Sub")
.select()
.execute(glue)
.await;

Derived Subquery with Offset and Limit

This example shows how to create a derived subquery combined with both the offset and limit methods to control the range of rows returned:

let actual = table("Item")
.select()
.offset(3)
.limit(1)
.alias_as("Sub")
.select()
.execute(glue)
.await;
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/ast-builder/statements/querying/data-aggregation/index.html b/docs/0.16.0/ast-builder/statements/querying/data-aggregation/index.html new file mode 100644 index 00000000..057844da --- /dev/null +++ b/docs/0.16.0/ast-builder/statements/querying/data-aggregation/index.html @@ -0,0 +1,17 @@ + + + + + +Data Aggregation | GlueSQL + + + + + +
+

Data Aggregation

The AST Builder API in GlueSQL allows you to construct SQL queries programmatically. This page provides an introduction to data aggregation using the AST Builder API.

Prerequisites

Before we explore data aggregation examples, let's set up a sample table called "User" with the following columns: "id" (INT), "name" (TEXT), and "age" (INT).

CREATE TABLE User (
id INT,
name TEXT,
age INT
);

We will use this table for the subsequent examples.

Grouping and Counting

To group records by a specific column and count the number of occurrences in each group, you can use the AST Builder's group_by() and project() methods.

table("User")
.select()
.group_by("age")
.project("age, count(*)")
.execute(glue);

The above code groups the records in the "User" table by the "age" column and returns the age value along with the count of occurrences in each group. The result would be:

age | count(*)
----|---------
20 | 1
30 | 2
50 | 2

Filtering Groups with HAVING

You can further filter the groups based on specific conditions using the having() method. The having() method allows you to apply conditions to the grouped data.

table("User")
.select()
.group_by("age")
.having("count(*) > 1")
.project("age, count(*)")
.execute(glue);

The above code groups the records in the "User" table by the "age" column, but it only includes groups where the count of occurrences is greater than 1. The result would be:

age | count(*)
----|---------
30 | 2
50 | 2

This concludes the introduction to data aggregation using the AST Builder API in GlueSQL. You can leverage these methods to perform various aggregations and analyze your data effectively.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/ast-builder/statements/querying/data-injection/index.html b/docs/0.16.0/ast-builder/statements/querying/data-injection/index.html new file mode 100644 index 00000000..30922914 --- /dev/null +++ b/docs/0.16.0/ast-builder/statements/querying/data-injection/index.html @@ -0,0 +1,17 @@ + + + + + +Data Injection | GlueSQL + + + + + + + + + + \ No newline at end of file diff --git a/docs/0.16.0/ast-builder/statements/querying/data-joining/index.html b/docs/0.16.0/ast-builder/statements/querying/data-joining/index.html new file mode 100644 index 00000000..60e80cc2 --- /dev/null +++ b/docs/0.16.0/ast-builder/statements/querying/data-joining/index.html @@ -0,0 +1,17 @@ + + + + + +Data Joining | GlueSQL + + + + + + + + + + \ No newline at end of file diff --git a/docs/0.16.0/ast-builder/statements/querying/data-selection-and-projection/index.html b/docs/0.16.0/ast-builder/statements/querying/data-selection-and-projection/index.html new file mode 100644 index 00000000..833c91fc --- /dev/null +++ b/docs/0.16.0/ast-builder/statements/querying/data-selection-and-projection/index.html @@ -0,0 +1,17 @@ + + + + + +Data Selection and Projection | GlueSQL + + + + + + + + + + \ No newline at end of file diff --git a/docs/0.16.0/ast-builder/statements/querying/data-sorting-and-limiting/index.html b/docs/0.16.0/ast-builder/statements/querying/data-sorting-and-limiting/index.html new file mode 100644 index 00000000..8bc2750f --- /dev/null +++ b/docs/0.16.0/ast-builder/statements/querying/data-sorting-and-limiting/index.html @@ -0,0 +1,17 @@ + + + + + +Data Sorting and Limiting | GlueSQL + + + + + + + + + + \ No newline at end of file diff --git a/docs/0.16.0/ast-builder/statements/querying/fetching-data-from-storage/index.html b/docs/0.16.0/ast-builder/statements/querying/fetching-data-from-storage/index.html new file mode 100644 index 00000000..b620e564 --- /dev/null +++ b/docs/0.16.0/ast-builder/statements/querying/fetching-data-from-storage/index.html @@ -0,0 +1,17 @@ + + + + + +Fetching Data from Storage | GlueSQL + + + + + +
+

Fetching Data from Storage

The AST Builder provides a powerful and flexible way to query data from your tables, similar to SQL's SELECT statement. This guide will show you how to use the AST Builder's table("foo").select() method to perform various query types, including filtering, joining, grouping, ordering, and pagination.

Basic SELECT

To perform a basic SELECT query using the AST Builder, simply call the select() method on a table object.

let actual = table("Category").select().execute(glue).await;

Filtering (WHERE)

To filter the results of a SELECT query, use the filter() method, providing a condition as a string.

let actual = table("Category")
.select()
.filter("name = 'Meat'")
.execute(glue)
.await;

Joining Tables

You can join tables using the join() or join_as() methods. The following example demonstrates an INNER JOIN:

let actual = table("Item")
.alias_as("i")
.select()
.join_as("Category", "c")
.on("c.id = i.category_id")
.filter("c.name = 'Fruit' OR c.name = 'Meat'")
.project("i.name AS item")
.project("c.name AS category")
.execute(glue)
.await;

For LEFT OUTER JOIN, use the left_join() method:

let actual = table("Category")
.select()
.left_join("Item")
.on(col("Category.id")
.eq(col("Item.category_id"))
.and(col("price").gt(50)))
.project(vec![
"Category.name AS category",
"Item.name AS item",
"price",
])
.execute(glue)
.await;

Grouping and Aggregating (GROUP BY, HAVING)

To group the results of a SELECT query, use the group_by() method. You can also filter the groups using the having() method.

let actual = table("Item")
.select()
.join("Category")
.on(col("Category.id").eq("Item.category_id"))
.group_by("Item.category_id")
.having("SUM(Item.price) > 80")
.project("Category.name AS category")
.project("SUM(Item.price) AS sum_price")
.execute(glue)
.await;

Sorting Results (ORDER BY)

To sort the results of a SELECT query, use the order_by() method.

let actual = table("Item")
.select()
.project("name, price")
.order_by("price DESC")
.execute(glue)
.await;

Pagination (OFFSET, LIMIT)

You can paginate the results of a SELECT query using the offset() and limit() methods.

let actual = table("Item")
.select()
.project("name, price")
.order_by("price DESC")
.offset(1)
.limit(2)
.execute(glue)
.await;
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/ast-builder/statements/querying/using-preloaded-data/index.html b/docs/0.16.0/ast-builder/statements/querying/using-preloaded-data/index.html new file mode 100644 index 00000000..094dfe99 --- /dev/null +++ b/docs/0.16.0/ast-builder/statements/querying/using-preloaded-data/index.html @@ -0,0 +1,17 @@ + + + + + +Using Preloaded Data | GlueSQL + + + + + +
+

Using Preloaded Data

This guide will show you how to use AST Builder to query data that has already been loaded into memory, as opposed to querying data from storage. This is similar to SQL's VALUES functionality.

Creating a Values Object

To create a values() object, you can either provide a vector of strings or a vector of vectors of strings. Each inner vector represents a row of data, and each string within the inner vector represents a value in that row.

use gluesql_core::ast_builder::values;

let actual = values(vec!["1, 'Glue'", "2, 'SQL'", "3, 'Rust'"])
.execute(glue)
.await;

let actual = values(vec![
vec!["1", "'Glue'"],
vec!["2", "'SQL'"],
vec!["3", "'Rust'"],
])
.execute(glue)
.await;

Sorting Results (ORDER BY)

To sort the results of a values() query, use the order_by() method.

let actual = values(vec!["1, 'Glue'", "2, 'SQL'", "3, 'Rust'"])
.order_by("column2 desc")
.execute(glue)
.await;

Pagination (OFFSET, LIMIT)

You can paginate the results of a values() query using the offset() and limit() methods.

let actual = values(vec!["1, 'Glue'", "2, 'SQL'", "3, 'Rust'"])
.offset(1)
.execute(glue)
.await;

let actual = values(vec!["1, 'Glue'", "2, 'SQL'", "3, 'Rust'"])
.limit(2)
.execute(glue)
.await;

Querying Preloaded Data

To query preloaded data using the values() object, you can call the select() method, and then use the project() method to specify the columns you want to include in the result.

let actual = values(vec!["1, 'Glue'", "2, 'SQL'", "3, 'Rust'"])
.alias_as("Sub")
.select()
.project("column1 AS id")
.project("column2 AS name")
.execute(glue)
.await;
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/blog/archive/index.html b/docs/0.16.0/blog/archive/index.html new file mode 100644 index 00000000..9771d822 --- /dev/null +++ b/docs/0.16.0/blog/archive/index.html @@ -0,0 +1,17 @@ + + + + + +Archive | GlueSQL + + + + + + + + + + \ No newline at end of file diff --git a/docs/0.16.0/blog/atom.xml b/docs/0.16.0/blog/atom.xml new file mode 100644 index 00000000..8a44075f --- /dev/null +++ b/docs/0.16.0/blog/atom.xml @@ -0,0 +1,102 @@ + + + https://gluesql.org/docs/0.16.0/blog + GlueSQL Blog + 2023-11-18T00:00:00.000Z + https://github.com/jpmonette/feed + + GlueSQL Blog + https://gluesql.org/docs/0.16.0/img/favicon.ico + + <![CDATA[Release v0.15]]> + https://gluesql.org/docs/0.16.0/blog/release-v0.15 + + 2023-11-18T00:00:00.000Z + + 🌊 Breaking Changes

🍀 Python Support

Code Samples

from gluesql import Glue, MemoryStorage
from tabulate import tabulate

db = Glue(MemoryStorage())

sql = """
SELECT
u.name as user,
d.name as device
FROM User u
JOIN Device d ON u.id = d.userId
""".strip().replace(
" ", ""
)

result = db.query(sql)
rows = result[0].get("rows")
print(f"\n[Query]\n{sql}")
print(tabulate(rows, headers="keys", showindex=True, tablefmt="simple_outline"))

🍀 Redis Storage

🍀 CSV Storage

🍀 More operators and functions

🚀 Features

  • feat: implement select iterator utility function @ever0de (#1429)

🌟 Improvements

🐛 Bug Fixes

  • fix: Literal comparison with BinaryOperator @ding-co (#1397)
  • fix: update Key.cmp to compare a type with other type @tgsong827 (#1367)
  • Fix Value::evaluate_cmp_with_literal between Decimal and Literal::Num… @panarch (#1352)
  • Fix spool on tabular off and SelectMap @devgony (#1314)
  • Update auto-assign-action to be triggered on PR open from fork repos @panarch (#1313)
  • Fix Scala Subquery should contain only 1 column @ChobobDev (#1284)
  • Wrap config path by quotes in auto-author-assign.yml @panarch (#1258)
  • Apply word-wrap to docs/ article h1 @panarch (#1230)
  • Fix docusaurus.config.js themeConfig handler @panarch (#1225)

👏 New Contributors

Full Changelog: https://github.com/gluesql/gluesql/compare/v0.14.0...v0.15.0

]]>
+ + Taehoon Moon + https://github.com/panarch + + + +
+ + <![CDATA[GlueSQL - Revolutionizing Databases by Unifying Query Interfaces]]> + https://gluesql.org/docs/0.16.0/blog/revolutionizing-databases-by-unifying-query-interfaces + + 2023-05-30T00:00:00.000Z + + Introduction

GlueSQL is a versatile database project designed for exceptional portability across a broad range of environments, from embedded systems and servers to web and mobile platforms. The core goal is to support diverse storage environments and manage various data types with a standard SQL approach.

Imagine handling files like CSV, JSONL, and Parquet, or transforming key-value or NoSQL databases such as RocksDB, Redis, and MongoDB into SQL-supporting databases—all feasible with GlueSQL. It can also operate with storages supported in web browsers.

GlueSQL's essential feature is providing a management layer for these diverse storage scenarios without requiring data migration. The broader aim is to facilitate portability of GlueSQL to any environment supporting read or read-write operations. This extends to APIs like GitHub, or messengers like Discord or Slack.

GlueSQL supports both structured and unstructured data and is written in Rust for compatibility with various environments. While portability is its core value, the emphasis is on creating an intuitive, comfortable development environment for easy custom storage implementation.

Ultimately, GlueSQL aims to significantly reduce the cost, time, and complexity of developing new databases. By leveraging GlueSQL for the parser, planner, and execution layer, developers can focus on creating specific storage implementations, leading to a more convenient query interface like SQL for many environments.

The Problem: Why Reinvent the Database?

Despite the numerous database implementations that currently exist, the emergence of new databases continues. The primary reason behind this trend is our need for databases for a broad spectrum of distinct purposes. For instance, new databases are surfacing that are specifically optimized for Large Language Models (LLMs) like ChatGPT. The range is wide and diverse, encompassing embedded databases, OLAP for data analysis, OLTP databases optimized for online transactions, databases specialized for time-series data processing, and many more.

With such varied requirements, we find ourselves in constant need of fresh databases. However, constructing a database from scratch is a monumental task. It necessitates defining a query interface for handling the database and implementing a corresponding parser. Moreover, a separate execution layer for running operations must be built. Also, the planning layer, which is responsible for devising execution strategies, is a vital aspect of this process. Let's not forget about the critical storage layer that physically reads and stores the data. In a nutshell, there's a daunting amount of work involved in developing a new database.

Given these circumstances, it's understandable why numerous emerging databases resort to high pricing structures—they need immediate revenue to offset continuous development costs.

But the story doesn't end here. Query interfaces like SQL are indeed useful for serious tasks, but they also provide excellent utility for handling simple log files such as CSV, JSONL, Parquet, and even for utilizing REST APIs for various applications. The issue arises when a complex query interface needs to be provided even for these lighter storage requirements—it necessitates a development process almost identical to building a sophisticated database. Implementing an entire parser and execution layer just to add SQL support to an existing service can seem like an excessive burden.

Whether it's a simple storage environment or a serious task, the key lies in the storage layer, which involves the actual reading and storing of data. So, what if developers focused on implementing these storage mechanisms while the remaining parts could be handled using existing libraries? This is the role that GlueSQL aspires to play.

The Vision of GlueSQL

The GlueSQL project aims to offer a unified query interface for various environments. The goal is to allow anyone to port and use SQL and GlueSQL's proprietary query builder, the AST Builder, in any desired environment. This could range from key-value databases, serious NoSQL databases, log files, and even REST API services. Essentially, if a service supports reading or read-writing data, regardless of the data type, it can readily support a complex query interface via GlueSQL.

Presently, the GlueSQL project itself directly supports a few storage types as reference storages. These include in-memory storage for non-persistent data handling, sled storage, which is a key-value database written in Rust, JSON storage for handling JSON and JSONL files, and a storage that ports SQL to the web browser's IndexedDB. While the GlueSQL Team is primarily developing these, the aim is to allow anyone to create such custom storages for a wide array of purposes, thus enabling them to assemble the database of their choosing.

Imagine using GlueSQL's SQL and AST Builder everywhere, with the simple method of swapping out storages to operate in diverse settings. It could significantly reduce software development costs. Developers wouldn't need to learn the different usage methods for each database. Instead, they could focus solely on implementing business logic using the same interface.

Our vision is to reduce database development costs by 10 times, or even more than 20 times. We aim to gather diverse database creators under the GlueSQL banner, making it the go-to solution for cost-effective database development.

Benefits to Database Users: Unifying Query Interfaces, Streamlining Software Development, and Reducing Costs

From the perspective of the users who engage with databases, there has always been the burden of learning different interfaces to interact with each database. The approach required to work with Redis is different from that necessary for MongoDB. Likewise, handling SQL databases necessitates using SQL. Although SQL databases generally use a common SQL, the SQL they support can considerably vary when examined in detail.

Naturally, there are legitimate reasons for such differences. Each database focuses on different areas, and to cater to specialized functionalities, they incorporate dedicated interface mechanisms. However, not all application development needs to utilize these database-specific core special functionalities.

Let's look at a couple of examples:

Suppose you're developing a back-end application that uses MySQL as the database and Redis for caching. Due to the vast differences in handling SQL databases and Redis, you would have to develop using different methods when storing data.

Here's another scenario: +Imagine you're implementing a data migration pipeline between various databases and log files. Let's say you're transferring Parquet to Redis or MongoDB. In this case, you would need to convert data using different methods for each, all of which would be a cumbersome process.

In both of the above examples, GlueSQL can directly address and solve the issues. It offers the convenience of a uniform query interface to deal with these matters. In certain scenarios, even the construction of a data pipeline can potentially be solved with a single SQL query, thanks to GlueSQL.

Benefits to Database Developers: Drastically Lowering Development Costs and Simplifying the Creation of Purpose-Built Databases

If you want to support SQL in the desired environment, using GlueSQL essentially requires you to implement an interface for Storage. There's no need to support all functionalities from the beginning. You can start lightly, choosing and implementing storage features suitable for the environment you want to create. To facilitate this, GlueSQL also provides a library in the form of a test suite to easily validate the storage you've implemented.

Lowering development costs in this way will enable a broader range of developers to support the GlueSQL query interface. As more developers join, a significant synergy can be generated. Designing a query interface from scratch involves a great deal of work, including planning and supporting the interface for different target programming languages.

However, despite all this hard work, it is not easy to attract database users accustomed to different methods.

Consider that the SQL and AST Builder provided by GlueSQL are already securing numerous users. This eliminates the need for efforts to promote a newly planned query interface. Over the years, many new databases have emphasized compatibility with PostgreSQL or MySQL for similar reasons. As GlueSQL places a strong emphasis on portability in its query interface planning, it allows for more flexible configuration according to the desired situation. Through the AST Builder, it also eliminates the cost of porting to different languages.

For many database developers, using GlueSQL can be an optimal choice, as it can save costs and quickly secure users.

Let me mention one more thing: what's convenient for humans... could be applied to AI as well. Rather than making AI write automation code using different databases, providing a common query interface can be much more efficient.

The Future with GlueSQL

GlueSQL has been and will continue to improve and develop new features to enable portability in various environments. Thanks to the schemaless data support added last year, it is now possible to handle both structured data with schema and unstructured data like JSON simultaneously. This has significantly increased the range of storage environments that can be supported.

One of the key features added last year was the AST Builder. This feature allowed us to escape the confines of SQL and provide an interface for comfortably handling data in the programming languages used for development.

Of course, improving existing features is extremely important, and there are many new features to be added. As a major development plan this year, we aim to develop features to effectively attach GlueSQL to NoSQL databases with their own planners and execution layers. The GlueSQL query planner, currently at a basic level, will see significant changes this year. With the expansion of this planner, not only NoSQL databases but also other SQL databases could be supported without sacrificing performance using GlueSQL.

The synergy that arises from the combination of different databases is a significant bonus in this process.

The Journey of the GlueSQL Team

The GlueSQL project was first conceived in the fall of 2019, and since then we have been developing it continuously. Personally, I have created various products in a variety of environments, including game development, backend server, and frontend development over the past decade. The experience gained through this process was a major motivation to start the GlueSQL project.

To put it grandly, the inconveniences felt while using different databases in various environments were a major motivation, wouldn't you say?

The start was actually a bit simple. Around 2019, I was mainly doing web front-end development. However, the lack of a structured database for state management and internal data processing made it very uncomfortable, especially since I couldn't use SQL databases and the like. So I started to lightly create an SQL database that could run on a web browser. Also, I wanted to use Rust, but after failing to introduce it at the company I was working for at the time, I decided to use it in my own project.

But as I started developing, my dreams grew significantly. Beyond a SQL database that simply operates on a web browser, I started envisioning a database that fits the name "Glue", one that can easily be ported to various environments, and I continue that journey to this day.

Whether I took the database project too lightly, or because the features I wanted kept increasing, the content to be developed kept expanding. As a result, I ended up investing full time in the GlueSQL project development for over three years. For a year in between, I even juggled full-time software engineering work alongside GlueSQL development. Currently, I'm back to developing the GlueSQL project full time, alongside various part-time contributors.

Now, we're getting very close to the starting point of the picture I wanted to create through GlueSQL, and thankfully, with contributors joining me, I am not alone.

The Sustainability and Business Aspect of GlueSQL

I believe that what we create through GlueSQL will make a great contribution to the world and make many software engineers happy. This gives me immense strength to continue developing even in difficult situations. However, we cannot accomplish everything with pure passion alone. As much as the GlueSQL project can make a significant contribution, I also see it as holding great business value.

The business strategy of GlueSQL may be somewhat different from other databases. We distribute the project itself as open source under the Apache-2.0 license, so that anyone can use it fully, and we do not consider pricing methods such as restricting features to the storages we support. In fact, if there is any player who can do it better, there's no way to prevent them from taking the GlueSQL project and making it their own.

But we believe that GlueSQL has great potential in this regard. Anyone can participate and they are free to distribute their own storage in the way they want, whether it's open source, private, or commercial. This eliminates the need to create something to replace the GlueSQL project. We aim to prevent the need to recreate the wheel that we provide using GlueSQL.

Moreover, our GlueSQL team seeks to continually expand our group of developers and companies working with us. During this development process, while they can certainly implement everything on their own, there is also no reason not to collaborate with our GlueSQL Team, especially for databases like NoSQL that have their own planners and execution layers. If you have a REST API and want to enhance convenience through SQL support, you can do it yourself or you can collaborate with us.

In addition, for some storages, we can also participate as players in the same position as other custom storage developers. We plan to expand the GlueSQL ecosystem in various ways, such as technical support and storage development.

We are finally ready to provide GlueSQL to users at the production level. We are accelerating the development of GlueSQL. If you are a company interested in storage development like SQL support, or if you resonate with our vision and want to join us, please contact us at taehoon@gluesql.com.

Conclusion

The continued emergence of new databases is driven by the demand for diverse and specialized databases, such as those optimized for Large Language Models (LLMs) and databases catering to unique requirements, like embedded databases, OLAP, OLTP, and time-series data processing. However, developing a new database from scratch is a significant undertaking, requiring extensive work, which often results in high costs.

GlueSQL presents a solution to this challenge by providing a unified query interface that can be ported across various environments, from key-value databases, NoSQL databases, log files, to REST APIs. It allows anyone to create custom storages, reducing the need for developers to build entirely new databases and to learn different usage methods for each database. Instead, they can focus on implementing their business logic using the same interface.

From a user perspective, GlueSQL offers the convenience of a unified query interface, easing the burden of learning different interfaces for each database. This simplification of interface use can also extend to AI, potentially enhancing the efficiency of AI automation.

GlueSQL's development plan includes significant enhancements to its query planner and aims to enable effective attachment of GlueSQL to NoSQL databases. The synergy of combining different databases is a valuable bonus in this process.

Since its inception in the fall of 2019, the GlueSQL team has continuously developed the project, driven by the desire to mitigate the inconveniences encountered while using different databases in various environments. The journey has been a rewarding one, with the GlueSQL project now at a point where it closely resembles the envisioned product.

GlueSQL, distributed under the Apache-2.0 license, is free for anyone to use and adapt. While the GlueSQL team welcomes collaboration with other developers and companies, they also see significant potential for the project as a business venture. The team is working to expand the GlueSQL ecosystem through a variety of initiatives, including technical support and storage development.

With GlueSQL now sufficiently prepared for practical applications, the team invites companies interested in storage development or those who share their vision to join them in their journey of revolutionizing database development.

]]>
+ + Taehoon Moon + https://github.com/panarch + + + + + +
+ + <![CDATA[Test-Driven Documentation - Automating User Manual Creation in GlueSQL]]> + https://gluesql.org/docs/0.16.0/blog/test-driven-documentation + + 2023-05-30T00:00:00.000Z + + Introduction: GlueSQL and Test-Driven Documentation

Recently, the GlueSQL project reached a significant milestone with the release of version 0.14. This new version brings a host of fresh features to the table, yet one of the most notable changes is in the realm of documentation. For the first time, we're proud to announce the launch of our official documentation website. Interested readers can explore the full range of user manuals at https://gluesql.org/docs.

Prior to this update, the only way to navigate GlueSQL was by manually inspecting the test code within the test suite. With the recent release, however, a comprehensive user manual has been made public to facilitate a more user-friendly experience. We hope that this new addition will prove beneficial to a broad spectrum of users.

The task of compiling an entire database manual in one go was daunting due to the sheer volume of content required. Surprisingly, this process turned out to be smoother than initially anticipated, largely due to the invaluable aid of ChatGPT, which was instrumental in automating much of the document creation. Specifically, around 80% of the SQL Syntax section was generated using this tool.

This remarkable feat was only possible due to the solid foundation of test codes previously established in GlueSQL. In this article, we'll share how we managed to leverage ChatGPT in such a unique way. Based on our recent experience of crafting documents grounded in testing, we've begun to consider the possibility of entirely automating document creation, save for the initial stages.

Along with sharing our journey so far, we will also reveal our plans for future test-based automation of documentation within GlueSQL.

Test Codes and Documentation

The GlueSQL project has placed a significant emphasis on writing test codes. This might be a given for a database project; however, the thoroughness of our approach is evident from our line coverage of nearly 99% for core codes. While we devoted considerable effort to creating these test codes, our primary focus has always been on a different aspect: ensuring that anyone can quickly grasp the content of the tests and easily add new ones.

The intent here is to empower newcomers to GlueSQL to understand the functionality of the software solely by examining integration tests, even in the absence of a user manual.

The integration tests for GlueSQL can be found in the test-suite workspace. For example, here's an excerpt of the test code for the INSERT statement:

test_case!(insert, async move {
run!(
"
CREATE TABLE Test (
id INTEGER DEFAULT 1,
num INTEGER NULL,
name TEXT NOT NULL,
);"
);

test! {
name: "basic insert - single item",
sql: "INSERT INTO Test (id, num, name) VALUES (1, 2, 'Hi boo');",
expected: Ok(Payload::Insert(1))
};


test! {
sql: "INSERT INTO Test VALUES(17, 30, 'Sullivan');",
expected: Ok(Payload::Insert(1))
};

test! {
sql: "INSERT INTO Test (num, name) VALUES (28, 'Wazowski');",
expected: Ok(Payload::Insert(1))
};

test! {
sql: "SELECT * FROM Test;",
expected: Ok(select!(
id | num | name;
I64 | I64 | Str;
1 2 "Hi boo".to_owned();
3 9 "Kitty!".to_owned();
2 7 "Monsters".to_owned();
17 30 "Sullivan".to_owned();
1 28 "Wazowski".to_owned()
))
};

// ...
});

Despite being written in Rust, these test cases are designed to be comprehensible, even to those unfamiliar with the language. Each test is a complete scenario from start to finish, and the results of each operation are readily observable.

Given that identifying results from SELECT operations in the form of Rust enums and structs can be challenging, we actively utilized macros such as select! and select_with_null!. We've composed the test cases to demonstrate that the INSERT statement can handle a wide range of cases, including specifying all columns, omitting some, or omitting all.

test! {
sql: "INSERT INTO Test (id, num) VALUES (1, 10);",
expected: Err(InsertError::LackOfRequiredColumn("name".to_owned()).into())
};

The tests also include scenarios for expected faulty inputs, indicating the error returns in these situations.

By organizing the tests in this manner, we aim to make it easy for anyone to read and write tests. Our goal was for these tests to serve as "documentation" for GlueSQL contributors. At the time we were writing these tests, we didn't anticipate that they could actually become documentation themselves. But we've come to realize that they have extraordinary potential.

Leveraging ChatGPT

When we first embarked on writing the User Manual, we were overwhelmed by the sheer volume of content we had to generate. Around the same time, ChatGPT was gaining prominence, and we thought it might be worth trying out, if only to lighten our load slightly.

To our surprise, ChatGPT exceeded our expectations. If the test codes were well written, it was capable of automatically crafting an exceptional document based on them, capturing all essential details.

After several trials and errors, we settled on the following prompt for document generation. While it's still a challenge to use the same prompt for all documentation, we made minor modifications to suit different situations:

I'm creating an SQL database documentation website, and I'd like you to help me with one of the pages that introduces the SQL syntax for GlueSQL.

1. Please provide the response content in the "markdown" format, so I can copy and paste it directly. Keep this constraint in mind while writing.
2. Regardless of the language I use, I need the content written in English.
3. I will provide some test case code written in the Rust language, which contains SQL examples. Please write the documentation based on these examples, but feel free to change the table names, column names, and data types as needed. Don't include any Rust related content or text in the response. all the response code example should be in plain SQL.
4. GlueSQL does not have the VARCHAR type. If you want to use that, please use TEXT instead. You don't need to mention this in the response.
5. Wrap the entire response text using <pre> and </pre> tags so I can copy all the content easily.

Now, I'd like you to write the following request:
SQL Statement - "INSERT"

Here's an example test code you can refer to:

test_case!(insert, async move {
run!(...

Generally, we used the template above, and copied and pasted the test code from our existing test-suite. We leveraged this method to harness our many tests to assist in the creation of the user manual. In the next section, we'll showcase a sample of the documentation generated in this manner. It's quite impressive.

Success Case: Automated User Manual of GlueSQL

Thanks to ChatGPT, the resulting INSERT document page can be viewed at the following link. It's important to note that we used ChatGPT 4 for this task. Version 3.5 wasn't quite up to the task, and using version 4 was the minimum requirement.

https://gluesql.org/docs/dev/sql-syntax/statements/data-manipulation/insert

INSERT Statement

The results were quite impressive. ChatGPT neatly categorized the test cases, explained the syntax, outlined constraints, and provided appropriate examples. It didn't stop there; it also skillfully recognized error test cases and incorporated them into the documentation, as shown below.

INSERT Statement

Isn't it amazing?

Future Plans: Fully Automating Documentation Generation

While the current documentation is far from perfect and there are many aspects that can be improved, we see great potential in this approach. We believe it's entirely possible to automate the process of writing this kind of document, and writing in general.

In the past, documents like user manuals required a great deal of effort to maintain once they were written. If a document contained real code examples, verifying that the code still worked was often a tedious task. With the ability to automatically generate documentation as we have done here, these issues are no longer problematic.

Previously, you would have to write tests and then also document them separately. If you had to support multiple languages, that would be an additional task. With a tool like ChatGPT, you can automate all of this. All a developer has to do is write the tests. This alone can be sufficient. You can generate documents automatically based on the tests. Eventually, we can even support automatically translating these documents into multiple languages.

The GlueSQL project repository is currently hosted on GitHub and makes good use of various GitHub Actions. We envision a GitHub Action that automatically regenerates a document corresponding to a test when a user modifies the test and raises a Pull Request. Another GitHub Action could automatically translate updated documents into supported languages and create new Pull Requests. The possibilities are truly endless.

Not only will this help with document generation, but it will also provide clear guidelines for writing better test code. If we can automatically generate documents based on written tests, the quality of those documents can serve as an indicator of the quality of the tests themselves. This means that a document automation tool can play the role of a good reviewer for tests. It can greatly reduce the time and effort required for painstakingly reviewing the quality of each test. Developers can also write tests without pressure, evaluate their test code by looking at the generated document, and improve it.

Furthermore, multi-language support becomes a breeze. In my personal experience as a software engineer over the past decade, developing various products such as games, web services, and applications, I often needed to support multiple languages. Each time, there was no definite solution. The optimal approach varied depending on the situation, and there were many things to consider when entrusting translations, such as effectively communicating the context of the target service to the translator. Moreover, regularly updating content and having it retranslated into various languages was a very tedious process. While I tried to automate as much as possible by creating various tools, I was never fully satisfied. I believe ChatGPT can completely solve these issues. If there is a need to provide project-specific context, all you need to do is prepare a prompt in advance. Instead of having to rely on and wait for professional translators, we can now entrust this task to ChatGPT, and we only need a few people to review the translated content.

We are nearing a world where documentation is no longer a burden for developers.

Conclusion: The Value of Test-Driven Documentation

The use of ChatGPT to generate documentation has proven a significant step forward in the GlueSQL user manual creation process. Through test-driven documentation, we've managed to automate a substantial part of the manual creation process, saving time and effort, and increasing accuracy.

Moreover, this process has unveiled a new potential for documentation: the possibility of fully automating document generation. We've seen that quality tests can become quality documentation with the help of AI, leading to more efficient workflows and possibly better test code as a result.

The journey doesn't stop here. We envision leveraging this capability further to auto-translate our documents into multiple languages, making our product more accessible to a global audience.

As we progress, we hope that our experience can inspire other developers to explore and embrace the benefits of AI-generated, test-driven documentation. It's not just about saving time—it's about improving the way we work, communicate, and share knowledge.

]]>
+ + Taehoon Moon + https://github.com/panarch + + + + + + + +
+ + <![CDATA[Breaking the Boundary between SQL and NoSQL Databases]]> + https://gluesql.org/docs/0.16.0/blog/breaking-the-boundary-between-sql-and-nosql + + 2023-05-29T00:00:00.000Z + + Introduction

The divide between SQL and NoSQL databases has often presented challenges in database management. GlueSQL, a unique database maker library, aims to blur this boundary, providing a versatile tool for handling these two distinct types of databases.

In this article, we explore how GlueSQL navigates the features of SQL and NoSQL databases, offering an integrated solution that promotes flexibility and efficiency. With its ability to unify disparate database types, GlueSQL heralds a new age of adaptable database creation and management.

The Interface Perspective: SQL & AST Builder

When we talk about SQL databases, it's almost a given that they support SQL - the standard query language. Although there are slight variations between databases, the convenience of using a similar SQL language across multiple databases cannot be overstated. However, from a software engineer's perspective, there's room for improvement. In most software development scenarios, a specific programming language is used. SQL is a separate language, which can cause friction when integrating it into your software. As a result, rather than using raw SQL, many developers employ query builders or ORMs to manipulate SQL conveniently using their preferred programming language. Although it's not efficient to generate SQL using a query builder and then parse it again in the database, it's a practical and effective choice.

On the other hand, NoSQL databases offer different mechanisms. Some of them have their own language similar to SQL, but most provide an interface library developed specifically for each programming language. While SQL databases rely on external query builder libraries to provide an interface for each programming language, NoSQL databases mostly develop and offer these libraries themselves. If we discount the convenience of SQL language, this is one of the major factors that make NoSQL databases more comfortable to use. Since query builder libraries supporting SQL databases often cater to multiple SQL databases, they are limited in fully supporting unique features of each database. NoSQL databases, on the other hand, can freely manage their interface libraries without these restrictions.

Providing a query interface for each programming language is not a fundamental difference between SQL and NoSQL, but we generally accept it implicitly.

Let's see what happens if we break down this boundary, using GlueSQL as an example. As you can see from the SQL postfix, GlueSQL supports SQL and can be classified as an SQL database.

CREATE TABLE Glue (id INTEGER, name TEXT);

INSERT INTO Glue VALUES (1, "hello"), (2, "gluesql");

SELECT * FROM Glue WHERE id = 1;

However, GlueSQL also supports its own query builder, like a NoSQL database. +(Currently, only Rust is supported, but we're working on adding support for other languages.)

table("Glue")
.create_table()
.add_column("id INTEGER")
.add_column("name TEXT")
.execute(glue)

table("Glue")
.insert()
.values(vec![
vec![num(1), text("hello")],
vec![num(2), text("gluesql")],
])
.execute(glue)
.await;

table("Glue")
.select()
.filter(col("id").eq(1))
.execute(glue)
.await;

Let's reconsider the implicit distinction between SQL and NoSQL. GlueSQL indeed supports SQL, but it also officially develops and offers its own query builder. This query builder is not a secondary tool for SQL. While most SQL query builder libraries ultimately generate SQL strings, GlueSQL's builder directly creates an AST (Abstract Structure Tree) that is used for execution within GlueSQL. Hence, we call it the AST Builder. This means SQL and the AST Builder are two equally supported interfaces in GlueSQL.

This also offers an additional advantage:

table("Glue")
.select()
// 1.
.filter(col("id").eq(1))
// 2.
.filter("id = 1")
.execute(glue)
.await;

Because GlueSQL already supports SQL, not only can you use the custom interface in the AST Builder, but you can also use familiar SQL syntax in part. Whether you use col("id").eq(1) or "id = 1", you can use it in the way you prefer. The AST Builder interface, although initially unfamiliar, allows a gradual migration similar to writing SQL for your convenience.

Thus, we've dismantled one of the implicit distinctions between SQL and NoSQL. However, it's more of an implicit differentiation than a fundamental one. There are more significant design differences that we'll explore next.

Structured & Unstructured Data

In this section, we'll discuss how SQL and NoSQL handle data. SQL generally deals with structured data, and recently, it's been made to support semi-structured data as well. On the other hand, NoSQL supports schemaless, unstructured data. Then, we'll explain in detail how GlueSQL handles these two types of data. The last part of this section will provide a segue into the next section where we'll discuss the decomposition of database functions.

When talking about SQL databases, one aspect is usually considered together: SQL databases have a defined schema.

CREATE TABLE Foo (
id INTEGER,
name TEXT,
rate FLOAT NULL
);

However, these days, SQL databases tend to support semi-structured data types, such as LIST or JSON. But, supporting completely schemaless, unstructured data is a different matter. SQL databases typically require a minimum schema.

What about NoSQL databases? As NoSQL databases vary significantly, we can't make definitive statements. But let's consider a typical document database like MongoDB. Unlike SQL databases, it doesn't enforce a schema. Essentially, you can insert any form of data directly. Often, NoSQL databases support schemaless data, but they lack features that enforce a schema like SQL. They generally support structure via validation methods, rather than structured access.

Is there no choice but to distinguish between structured data and unstructured, schemaless data so clearly? GlueSQL is being developed with the goal of being adaptable in various environments. Being forced to choose regarding this schema constraint was quite inconvenient. We started pondering if we couldn't benefit from both aspects - supporting both schema and schemaless data simultaneously, and we eventually found the answer. Let's look at how GlueSQL currently solves this issue through familiar SQL examples.

CREATE TABLE Names (id INTEGER, name TEXT);
INSERT INTO Names VALUES (1, 'glue'), (2, 'sql');

You can create a regular table with a schema like this. But GlueSQL's choice for creating a schemaless table is as follows:

CREATE TABLE Logs;
INSERT INTO Logs VALUES
('{ "id": 1, "value": 30 }'),
('{ "id": 2, "rate": 3.0, "list": [1, 2, 3] }'),
('{ "id": 3, "rate": 5.0, "value": 100 }');

It creates a table without column definitions! If you do this, GlueSQL recognizes the table as schemaless and processes it internally.

SELECT id, rate, list[0] FROM Logs WHERE id = 2;

Although the way to create the table was a bit special, using it isn't much different from the regular SQL SELECT statement. Not only can you differentiate between schema and schemaless when creating tables, but you can also use them interchangeably!

SELECT * FROM Names JOIN Logs ON Names.id = Logs.id;
/*
| id | list | name | rate | value |
|----|---------|------|------|-------|
| 1 | | glue | | 30 |
| 2 |[1, 2, 3]| sql | 3 | |
*/

Here's an example of querying data by INNER JOINing the Names table, which has a schema, and the Logs table, which is schemaless. GlueSQL has resolved this problem by allowing the internal execution layer to handle both vector-type data, for cases where each row has a defined schema, and map-type data for schemaless cases.

Thanks to this, the variety of storage that can be supported through GlueSQL has expanded significantly. If there were previously limitations to supporting NoSQL databases that support schemaless data, that is no longer the case. The reference storage where you can directly experience this schemaless data support is JSON Storage. It offers features that allow you to deal directly with unstructured data like JSON using GlueSQL.

If GlueSQL starts from the perspective of an SQL database and expands, by providing the AST Builder directly, it once blurs the boundary, and by supporting unstructured data simultaneously, it knocks down the boundary once more. How do you like it?

Decomposing Database Functionality: Breaking Down SQL and NoSQL Features

The distinction between SQL and NoSQL is not just about whether they support unstructured data. Of course, there are examples like unstructured data, which is mainly supported only in NoSQL, but in many cases, SQL databases tend to support more diverse and complex queries. NoSQL often gains other advantages in exchange for reducing the range of query support provided by SQL databases.

GlueSQL is ambitious. It has devised a rather interesting method to support all of this through SQL and the AST Builder, with the same interface. When we usually say SQL database, it implicitly assumes that a lot of features have been fully implemented. Create tables by specifying a schema, modify schemas with "alter table", support both clustered and non-clustered indexes, and support transactions. And there's so much more. But the functionality that is naturally supported in SQL databases may not be natural in other environments.

Let's think about JSON Storage. GlueSQL's JSON Storage allows you to handle JSON, JSONL files using SQL and the AST Builder. This JSON Storage does not support atomic operations or transactions. Of course, it would be great if it did, but implementing and executing them would be a significant performance burden. In most cases, when you want to simply browse and handle JSONL files, the overhead caused by transactions can be an unnecessary burden. In this case, you want to handle JSON, JSONL files using SQL, but you don't necessarily need transactions.

To meet the requirements of these diverse environments, GlueSQL has separated the functionality of what we usually call an SQL database into multiple independent interfaces. +Store, StoreMut, AlterTable, Transaction, .. +These are just a few of the various storage interfaces that GlueSQL currently supports. +The way it works can be summarized like this: +If you implement Store, you can use SELECT. +And if you implement both Store and StoreMut, you can support quite a number of basic SQL statements including SELECT. +You can manage tables with CREATE TABLE, DROP TABLE, and handle data using INSERT, UPDATE, DELETE statements. +If you only need to retrieve data, you only need to implement Store. +If you want to support the ALTER TABLE statement, you can additionally implement the AlterTable interface. +The Transaction interface works the same way. +The interesting part is that, except for Store and StoreMut, all other storage interfaces can be implemented independently. GlueSQL allows you to choose and implement only the features you need. +And it's not just about providing interfaces. It also provides integration tests suitable for each situation to verify what you have implemented. You just need to implement the interface and import the corresponding test case for verification.

In addition to supporting both structured and unstructured data simultaneously, GlueSQL provides the ability to divide the functionality of a database into multiple independent features and selectively implement them. This allows GlueSQL to be ported to a wide variety of environments without any burden.

Conclusion

GlueSQL, while serving as a database that provides its own reference storage, is fundamentally a library designed to simplify the creation of databases. One of the substantial challenges GlueSQL had to overcome in order to support a diverse array of environments was to address the distinctive features that separate conventional SQL databases from NoSQL databases. GlueSQL achieved this through several innovative approaches, managing to support both categories simultaneously despite their significantly different characteristics.

It offers support for SQL alongside an AST Builder, and accommodates both structured and unstructured data. Additionally, it decomposes database functionalities into multiple independent features, allowing each environment to selectively implement the functionalities it requires.

These unique attributes enable GlueSQL to live up to its 'Glue' prefix by facilitating effortless porting across various environments. While we have been developing it for several years, there is still much ground to cover. However, the fact that we are now able to introduce it publicly attests to our successful technological validation and completion of a demonstrable level of implementation.

Through GlueSQL, we hope to provide developers with a unified query interface that can be customized according to their needs, thereby enabling them to produce efficient products more effortlessly. There's a promising future ahead for GlueSQL, and we look forward to its contributions to the technology community.

]]>
+ + Taehoon Moon + https://github.com/panarch + + + + +
+ + <![CDATA[Release v0.14]]> + https://gluesql.org/docs/0.16.0/blog/release-v0.14 + + 2023-05-27T00:00:00.000Z + + We now provide an official documentation website at https://gluesql.org/docs

🚀 Features

🍀 Schemaless data support

GlueSQL now supports creating tables without a schema, allowing for both structured and unstructured data to be stored in the same table. +To create a schemaless table, simply run CREATE TABLE without specifying any columns. For more information on querying schemaless data, please refer to the following link: querying schemaless data

CREATE TABLE Bar;

To insert values,

INSERT INTO Bar VALUES
('{ "name": "ast", "value": 30 }'),
('{ "name": "glue", "rate": 3.0, "list": [1, 2, 3] }'),

Then, selecting values from schemaless table is simple.

SELECT name, rate, list[0] FROM Bar WHERE name = 'glue';

e.g.

CREATE TABLE Names (id INTEGER, name TEXT);
INSERT INTO Names VALUES (1, 'glue'), (2, 'sql');

CREATE TABLE Logs;
INSERT INTO Logs VALUES
('{ "id": 1, "value": 30 }'),
('{ "id": 2, "rate": 3.0, "list": [1, 2, 3] }'),
('{ "id": 3, "rate": 5.0, "value": 100 }');

SELECT * FROM Names JOIN Logs ON Names.id = Logs.id;
/*
| id | list | name | rate | value |
|----|---------|------|------|-------|
| 1 | | glue | | 30 |
| 2 |[1, 2, 3]| sql | 3 | |
*/

🍀 IndexedDB & WebStorage supports in JavaScript package

GlueSQL supports handling in-memory, localStorage, sessionStorage, and even IndexedDB using the same SQL syntax. All you need to know is how to specify the ENGINE when creating a table.

e.g.

CREATE TABLE Mem (mid INTEGER) ENGINE = memory;
CREATE TABLE Loc (lid INTEGER) ENGINE = localStorage;
CREATE TABLE Ses (sid INTEGER) ENGINE = sessionStorage;
CREATE TABLE Idb (iid INTEGER) ENGINE = indexedDB;

SELECT
mid, lid, sid, iid
FROM Mem
JOIN Loc
JOIN Ses
JOIN Idb;

🍀 Data Types - UINT32, UINT64, UINT128, POINT and FLOAT32

🍀 Functions - APPEND, PREPEND, RAND, FIND_IDX, INITCAP and CALC_DISTANCE

🍀 Store traits

User-level custom function

By implementing both the CustomFunction and CustomFunctionMut traits, users can create, use, and delete user-level custom functions. Although GlueSQL plans to continuously add various functions, users may still find them insufficient. In such cases, users can create their own user-level custom functions to supplement the built-in functions. Additionally, if there are repetitive business logic codes, they can be stored as custom functions. +e.g.

CREATE FUNCTION ADD_ONE (n INT, x INT DEFAULT 1) RETURN n + x;

SELECT ADD_ONE(10) AS test;

DROP FUNCTION ADD_ONE;

Metadata

The Metadata trait is an optional implementation for providing additional metadata support in GlueSQL. GlueSQL does not enforce any specific metadata implementation, allowing custom storage developers to decide which type of metadata, such as create time, modify time, etc., they want to provide.

🍀 Storages

JSON Storage

Composite Storage

  • Add CompositeStorage which bundles multiple storages @panarch (#1068)

IndexedDB Storage

Web Storage

  • Add WebStorage - support localStorage \& sessionStorage for web browsers @panarch (#1050)

🍀 Other new features

🌊 Interface Changes

  • Remove Store trait related cfg features, @panarch (#1091)
  • Refactor CreateTable.columns from Vec<ColumnDef> to Option<Vec<ColumnDef>> @devgony (#1086)
  • Remove MutResult @panarch (#1073)
  • Update all store mut trait methods to take \&mut self @panarch (#1072)
  • Change StoreMut interface to use \&mut self, not to take ownership @panarch (#1071)
  • Modify default ColumnOption from NOT NULL to NULL @devgony (#997)

🌟 Improvements

🌳 Documentation

We now provide an official documentation website at https://gluesql.org/docs

Docs - setup

📋 Tests

🐛 Bug Fixes

  • Fix docusaurus pages/index broken link @panarch (#1214)
  • Fix docs/ Discord GlueSQL channel invite link address @panarch (#1213)
  • Fix InvalidJsonString error message replacing payload to fileName @devgony (#1185)
  • Fix TryFrom Value::Str to u128 not to use parse_uuid @ChobobDev (#1134)
  • Fix column alias with identifer for TableFactor::Derived @ding-young (#1119)
  • Pass data even when deleted_by is not present @ever0de (#1117)
  • Fix MemoryStorage \& WebStorage primary key support @panarch (#1115)
  • Fix plan::validate to handle CTAS and ITAS adding unit test @devgony (#1074)
  • Fix test-suite tester functions to show (found, expected) shape @panarch (#1028)
]]>
+ + Taehoon Moon + https://github.com/panarch + + + +
+
\ No newline at end of file diff --git a/docs/0.16.0/blog/breaking-the-boundary-between-sql-and-nosql/index.html b/docs/0.16.0/blog/breaking-the-boundary-between-sql-and-nosql/index.html new file mode 100644 index 00000000..549dcd3f --- /dev/null +++ b/docs/0.16.0/blog/breaking-the-boundary-between-sql-and-nosql/index.html @@ -0,0 +1,29 @@ + + + + + +Breaking the Boundary between SQL and NoSQL Databases | GlueSQL + + + + + +
+

Breaking the Boundary between SQL and NoSQL Databases

· 11 min read
Taehoon Moon

Introduction

The divide between SQL and NoSQL databases has often presented challenges in database management. GlueSQL, a unique database maker library, aims to blur this boundary, providing a versatile tool for handling these two distinct types of databases.

In this article, we explore how GlueSQL navigates the features of SQL and NoSQL databases, offering an integrated solution that promotes flexibility and efficiency. With its ability to unify disparate database types, GlueSQL heralds a new age of adaptable database creation and management.

The Interface Perspective: SQL & AST Builder

When we talk about SQL databases, it's almost a given that they support SQL - the standard query language. Although there are slight variations between databases, the convenience of using a similar SQL language across multiple databases cannot be overstated. However, from a software engineer's perspective, there's room for improvement. In most software development scenarios, a specific programming language is used. SQL is a separate language, which can cause friction when integrating it into your software. As a result, rather than using raw SQL, many developers employ query builders or ORMs to manipulate SQL conveniently using their preferred programming language. Although it's not efficient to generate SQL using a query builder and then parse it again in the database, it's a practical and effective choice.

On the other hand, NoSQL databases offer different mechanisms. Some of them have their own language similar to SQL, but most provide an interface library developed specifically for each programming language. While SQL databases rely on external query builder libraries to provide an interface for each programming language, NoSQL databases mostly develop and offer these libraries themselves. If we discount the convenience of SQL language, this is one of the major factors that make NoSQL databases more comfortable to use. Since query builder libraries supporting SQL databases often cater to multiple SQL databases, they are limited in fully supporting unique features of each database. NoSQL databases, on the other hand, can freely manage their interface libraries without these restrictions.

Providing a query interface for each programming language is not a fundamental difference between SQL and NoSQL, but we generally accept it implicitly.

Let's see what happens if we break down this boundary, using GlueSQL as an example. As you can see from the SQL postfix, GlueSQL supports SQL and can be classified as an SQL database.

CREATE TABLE Glue (id INTEGER, name TEXT);

INSERT INTO Glue VALUES (1, "hello"), (2, "gluesql");

SELECT * FROM Glue WHERE id = 1;

However, GlueSQL also supports its own query builder, like a NoSQL database. +(Currently, only Rust is supported, but we're working on adding support for other languages.)

table("Glue")
.create_table()
.add_column("id INTEGER")
.add_column("name TEXT")
.execute(glue)

table("Glue")
.insert()
.values(vec![
vec![num(1), text("hello")],
vec![num(2), text("gluesql")],
])
.execute(glue)
.await;

table("Glue")
.select()
.filter(col("id").eq(1))
.execute(glue)
.await;

Let's reconsider the implicit distinction between SQL and NoSQL. GlueSQL indeed supports SQL, but it also officially develops and offers its own query builder. This query builder is not a secondary tool for SQL. While most SQL query builder libraries ultimately generate SQL strings, GlueSQL's builder directly creates an AST (Abstract Structure Tree) that is used for execution within GlueSQL. Hence, we call it the AST Builder. This means SQL and the AST Builder are two equally supported interfaces in GlueSQL.

This also offers an additional advantage:

table("Glue")
.select()
// 1.
.filter(col("id").eq(1))
// 2.
.filter("id = 1")
.execute(glue)
.await;

Because GlueSQL already supports SQL, not only can you use the custom interface in the AST Builder, but you can also use familiar SQL syntax in part. Whether you use col("id").eq(1) or "id = 1", you can use it in the way you prefer. The AST Builder interface, although initially unfamiliar, allows a gradual migration similar to writing SQL for your convenience.

Thus, we've dismantled one of the implicit distinctions between SQL and NoSQL. However, it's more of an implicit differentiation than a fundamental one. There are more significant design differences that we'll explore next.

Structured & Unstructured Data

In this section, we'll discuss how SQL and NoSQL handle data. SQL generally deals with structured data, and recently, it's been made to support semi-structured data as well. On the other hand, NoSQL supports schemaless, unstructured data. Then, we'll explain in detail how GlueSQL handles these two types of data. The last part of this section will provide a segue into the next section where we'll discuss the decomposition of database functions.

When talking about SQL databases, one aspect is usually considered together: SQL databases have a defined schema.

CREATE TABLE Foo (
id INTEGER,
name TEXT,
rate FLOAT NULL
);

However, these days, SQL databases tend to support semi-structured data types, such as LIST or JSON. But, supporting completely schemaless, unstructured data is a different matter. SQL databases typically require a minimum schema.

What about NoSQL databases? As NoSQL databases vary significantly, we can't make definitive statements. But let's consider a typical document database like MongoDB. Unlike SQL databases, it doesn't enforce a schema. Essentially, you can insert any form of data directly. Often, NoSQL databases support schemaless data, but they lack features that enforce a schema like SQL. They generally support structure via validation methods, rather than structured access.

Is there no choice but to distinguish between structured data and unstructured, schemaless data so clearly? GlueSQL is being developed with the goal of being adaptable in various environments. Being forced to choose regarding this schema constraint was quite inconvenient. We started pondering if we couldn't benefit from both aspects - supporting both schema and schemaless data simultaneously, and we eventually found the answer. Let's look at how GlueSQL currently solves this issue through familiar SQL examples.

CREATE TABLE Names (id INTEGER, name TEXT);
INSERT INTO Names VALUES (1, 'glue'), (2, 'sql');

You can create a regular table with a schema like this. But GlueSQL's choice for creating a schemaless table is as follows:

CREATE TABLE Logs;
INSERT INTO Logs VALUES
('{ "id": 1, "value": 30 }'),
('{ "id": 2, "rate": 3.0, "list": [1, 2, 3] }'),
('{ "id": 3, "rate": 5.0, "value": 100 }');

It creates a table without column definitions! If you do this, GlueSQL recognizes the table as schemaless and processes it internally.

SELECT id, rate, list[0] FROM Logs WHERE id = 2;

Although the way to create the table was a bit special, using it isn't much different from the regular SQL SELECT statement. Not only can you differentiate between schema and schemaless when creating tables, but you can also use them interchangeably!

SELECT * FROM Names JOIN Logs ON Names.id = Logs.id;
/*
| id | list | name | rate | value |
|----|---------|------|------|-------|
| 1 | | glue | | 30 |
| 2 |[1, 2, 3]| sql | 3 | |
*/

Here's an example of querying data by INNER JOINing the Names table, which has a schema, and the Logs table, which is schemaless. GlueSQL has resolved this problem by allowing the internal execution layer to handle both vector-type data, for cases where each row has a defined schema, and map-type data for schemaless cases.

Thanks to this, the variety of storage that can be supported through GlueSQL has expanded significantly. If there were previously limitations to supporting NoSQL databases that support schemaless data, that is no longer the case. The reference storage where you can directly experience this schemaless data support is JSON Storage. It offers features that allow you to deal directly with unstructured data like JSON using GlueSQL.

If GlueSQL starts from the perspective of an SQL database and expands, by providing the AST Builder directly, it once blurs the boundary, and by supporting unstructured data simultaneously, it knocks down the boundary once more. How do you like it?

Decomposing Database Functionality: Breaking Down SQL and NoSQL Features

The distinction between SQL and NoSQL is not just about whether they support unstructured data. Of course, there are examples like unstructured data, which is mainly supported only in NoSQL, but in many cases, SQL databases tend to support more diverse and complex queries. NoSQL often gains other advantages in exchange for reducing the range of query support provided by SQL databases.

GlueSQL is ambitious. It has devised a rather interesting method to support all of this through SQL and the AST Builder, with the same interface. When we usually say SQL database, it implicitly assumes that a lot of features have been fully implemented. Create tables by specifying a schema, modify schemas with "alter table", support both clustered and non-clustered indexes, and support transactions. And there's so much more. But the functionality that is naturally supported in SQL databases may not be natural in other environments.

Let's think about JSON Storage. GlueSQL's JSON Storage allows you to handle JSON, JSONL files using SQL and the AST Builder. This JSON Storage does not support atomic operations or transactions. Of course, it would be great if it did, but implementing and executing them would be a significant performance burden. In most cases, when you want to simply browse and handle JSONL files, the overhead caused by transactions can be an unnecessary burden. In this case, you want to handle JSON, JSONL files using SQL, but you don't necessarily need transactions.

To meet the requirements of these diverse environments, GlueSQL has separated the functionality of what we usually call an SQL database into multiple independent interfaces. +Store, StoreMut, AlterTable, Transaction, .. +These are just a few of the various storage interfaces that GlueSQL currently supports. +The way it works can be summarized like this: +If you implement Store, you can use SELECT. +And if you implement both Store and StoreMut, you can support quite a number of basic SQL statements including SELECT. +You can manage tables with CREATE TABLE, DROP TABLE, and handle data using INSERT, UPDATE, DELETE statements. +If you only need to retrieve data, you only need to implement Store. +If you want to support the ALTER TABLE statement, you can additionally implement the AlterTable interface. +The Transaction interface works the same way. +The interesting part is that, except for Store and StoreMut, all other storage interfaces can be implemented independently. GlueSQL allows you to choose and implement only the features you need. +And it's not just about providing interfaces. It also provides integration tests suitable for each situation to verify what you have implemented. You just need to implement the interface and import the corresponding test case for verification.

In addition to supporting both structured and unstructured data simultaneously, GlueSQL provides the ability to divide the functionality of a database into multiple independent features and selectively implement them. This allows GlueSQL to be ported to a wide variety of environments without any burden.

Conclusion

GlueSQL, while serving as a database that provides its own reference storage, is fundamentally a library designed to simplify the creation of databases. One of the substantial challenges GlueSQL had to overcome in order to support a diverse array of environments was to address the distinctive features that separate conventional SQL databases from NoSQL databases. GlueSQL achieved this through several innovative approaches, managing to support both categories simultaneously despite their significantly different characteristics.

It offers support for SQL alongside an AST Builder, and accommodates both structured and unstructured data. Additionally, it decomposes database functionalities into multiple independent features, allowing each environment to selectively implement the functionalities it requires.

These unique attributes enable GlueSQL to live up to its 'Glue' prefix by facilitating effortless porting across various environments. While we have been developing it for several years, there is still much ground to cover. However, the fact that we are now able to introduce it publicly attests to our successful technological validation and completion of a demonstrable level of implementation.

Through GlueSQL, we hope to provide developers with a unified query interface that can be customized according to their needs, thereby enabling them to produce efficient products more effortlessly. There's a promising future ahead for GlueSQL, and we look forward to its contributions to the technology community.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/blog/index.html b/docs/0.16.0/blog/index.html new file mode 100644 index 00000000..37b55bd5 --- /dev/null +++ b/docs/0.16.0/blog/index.html @@ -0,0 +1,32 @@ + + + + + +Blog | GlueSQL + + + + + +
+

· 6 min read
Taehoon Moon

🌊 Breaking Changes

🍀 Python Support

Code Samples

from gluesql import Glue, MemoryStorage
from tabulate import tabulate

db = Glue(MemoryStorage())

sql = """
SELECT
u.name as user,
d.name as device
FROM User u
JOIN Device d ON u.id = d.userId
""".strip().replace(
" ", ""
)

result = db.query(sql)
rows = result[0].get("rows")
print(f"\n[Query]\n{sql}")
print(tabulate(rows, headers="keys", showindex=True, tablefmt="simple_outline"))

🍀 Redis Storage

🍀 CSV Storage

🍀 More operators and functions

🚀 Features

  • feat: implement select iterator utility function @ever0de (#1429)

🌟 Improvements

🐛 Bug Fixes

  • fix: Literal comparison with BinaryOperator @ding-co (#1397)
  • fix: update Key.cmp to compare a type with other type @tgsong827 (#1367)
  • Fix Value::evaluate_cmp_with_literal between Decimal and Literal::Num… @panarch (#1352)
  • Fix spool on tabular off and SelectMap @devgony (#1314)
  • Update auto-assign-action to be triggered on PR open from fork repos @panarch (#1313)
  • Fix Scala Subquery should contain only 1 column @ChobobDev (#1284)
  • Wrap config path by quotes in auto-author-assign.yml @panarch (#1258)
  • Apply word-wrap to docs/ article h1 @panarch (#1230)
  • Fix docusaurus.config.js themeConfig handler @panarch (#1225)

👏 New Contributors

Full Changelog: https://github.com/gluesql/gluesql/compare/v0.14.0...v0.15.0

· 14 min read
Taehoon Moon

Introduction

GlueSQL is a versatile database project designed for exceptional portability across a broad range of environments, from embedded systems and servers to web and mobile platforms. The core goal is to support diverse storage environments and manage various data types with a standard SQL approach.

Imagine handling files like CSV, JSONL, and Parquet, or transforming key-value or NoSQL databases such as RocksDB, Redis, and MongoDB into SQL-supporting databases—all feasible with GlueSQL. It can also operate with storages supported in web browsers.

GlueSQL's essential feature is providing a management layer for these diverse storage scenarios without requiring data migration. The broader aim is to facilitate portability of GlueSQL to any environment supporting read or read-write operations. This extends to APIs like GitHub, or messengers like Discord or Slack.

GlueSQL supports both structured and unstructured data and is written in Rust for compatibility with various environments. While portability is its core value, the emphasis is on creating an intuitive, comfortable development environment for easy custom storage implementation.

Ultimately, GlueSQL aims to significantly reduce the cost, time, and complexity of developing new databases. By leveraging GlueSQL for the parser, planner, and execution layer, developers can focus on creating specific storage implementations, leading to a more convenient query interface like SQL for many environments.

The Problem: Why Reinvent the Database?

Despite the numerous database implementations that currently exist, the emergence of new databases continues. The primary reason behind this trend is our need for databases for a broad spectrum of distinct purposes. For instance, new databases are surfacing that are specifically optimized for Large Language Models (LLMs) like ChatGPT. The range is wide and diverse, encompassing embedded databases, OLAP for data analysis, OLTP databases optimized for online transactions, databases specialized for time-series data processing, and many more.

With such varied requirements, we find ourselves in constant need of fresh databases. However, constructing a database from scratch is a monumental task. It necessitates defining a query interface for handling the database and implementing a corresponding parser. Moreover, a separate execution layer for running operations must be built. Also, the planning layer, which is responsible for devising execution strategies, is a vital aspect of this process. Let's not forget about the critical storage layer that physically reads and stores the data. In a nutshell, there's a daunting amount of work involved in developing a new database.

Given these circumstances, it's understandable why numerous emerging databases resort to high pricing structures—they need immediate revenue to offset continuous development costs.

But the story doesn't end here. Query interfaces like SQL are indeed useful for serious tasks, but they also provide excellent utility for handling simple log files such as CSV, JSONL, Parquet, and even for utilizing REST APIs for various applications. The issue arises when a complex query interface needs to be provided even for these lighter storage requirements—it necessitates a development process almost identical to building a sophisticated database. Implementing an entire parser and execution layer just to add SQL support to an existing service can seem like an excessive burden.

Whether it's a simple storage environment or a serious task, the key lies in the storage layer, which involves the actual reading and storing of data. So, what if developers focused on implementing these storage mechanisms while the remaining parts could be handled using existing libraries? This is the role that GlueSQL aspires to play.

The Vision of GlueSQL

The GlueSQL project aims to offer a unified query interface for various environments. The goal is to allow anyone to port and use SQL and GlueSQL's proprietary query builder, the AST Builder, in any desired environment. This could range from key-value databases, serious NoSQL databases, log files, and even REST API services. Essentially, if a service supports reading or read-writing data, regardless of the data type, it can readily support a complex query interface via GlueSQL.

Presently, the GlueSQL project itself directly supports a few storage types as reference storages. These include in-memory storage for non-persistent data handling, sled storage, which is a key-value database written in Rust, JSON storage for handling JSON and JSONL files, and a storage that ports SQL to the web browser's IndexedDB. While the GlueSQL Team is primarily developing these, the aim is to allow anyone to create such custom storages for a wide array of purposes, thus enabling them to assemble the database of their choosing.

Imagine using GlueSQL's SQL and AST Builder everywhere, with the simple method of swapping out storages to operate in diverse settings. It could significantly reduce software development costs. Developers wouldn't need to learn the different usage methods for each database. Instead, they could focus solely on implementing business logic using the same interface.

Our vision is to reduce database development costs by 10 times, or even more than 20 times. We aim to gather diverse database creators under the GlueSQL banner, making it the go-to solution for cost-effective database development.

Benefits to Database Users: Unifying Query Interfaces, Streamlining Software Development, and Reducing Costs

From the perspective of the users who engage with databases, there has always been the burden of learning different interfaces to interact with each database. The approach required to work with Redis is different from that necessary for MongoDB. Likewise, handling SQL databases necessitates using SQL. Although SQL databases generally use a common SQL, the SQL they support can considerably vary when examined in detail.

Naturally, there are legitimate reasons for such differences. Each database focuses on different areas, and to cater to specialized functionalities, they incorporate dedicated interface mechanisms. However, not all application development needs to utilize these database-specific core special functionalities.

Let's look at a couple of examples:

Suppose you're developing a back-end application that uses MySQL as the database and Redis for caching. Due to the vast differences in handling SQL databases and Redis, you would have to develop using different methods when storing data.

Here's another scenario: +Imagine you're implementing a data migration pipeline between various databases and log files. Let's say you're transferring Parquet to Redis or MongoDB. In this case, you would need to convert data using different methods for each, all of which would be a cumbersome process.

In both of the above examples, GlueSQL can directly address and solve the issues. It offers the convenience of a uniform query interface to deal with these matters. In certain scenarios, even the construction of a data pipeline can potentially be solved with a single SQL query, thanks to GlueSQL.

Benefits to Database Developers: Drastically Lowering Development Costs and Simplifying the Creation of Purpose-Built Databases

If you want to support SQL in the desired environment, using GlueSQL essentially requires you to implement an interface for Storage. There's no need to support all functionalities from the beginning. You can start lightly, choosing and implementing storage features suitable for the environment you want to create. To facilitate this, GlueSQL also provides a library in the form of a test suite to easily validate the storage you've implemented.

Lowering development costs in this way will enable a broader range of developers to support the GlueSQL query interface. As more developers join, a significant synergy can be generated. Designing a query interface from scratch involves a great deal of work, including planning and supporting the interface for different target programming languages.

However, despite all this hard work, it is not easy to attract database users accustomed to different methods.

Consider that the SQL and AST Builder provided by GlueSQL are already securing numerous users. This eliminates the need for efforts to promote a newly planned query interface. Over the years, many new databases have emphasized compatibility with PostgreSQL or MySQL for similar reasons. As GlueSQL places a strong emphasis on portability in its query interface planning, it allows for more flexible configuration according to the desired situation. Through the AST Builder, it also eliminates the cost of porting to different languages.

For many database developers, using GlueSQL can be an optimal choice, as it can save costs and quickly secure users.

Let me mention one more thing: what's convenient for humans... could be applied to AI as well. Rather than making AI write automation code using different databases, providing a common query interface can be much more efficient.

The Future with GlueSQL

GlueSQL has been and will continue to improve and develop new features to enable portability in various environments. Thanks to the schemaless data support added last year, it is now possible to handle both structured data with schema and unstructured data like JSON simultaneously. This has significantly increased the range of storage environments that can be supported.

One of the key features added last year was the AST Builder. This feature allowed us to escape the confines of SQL and provide an interface for comfortably handling data in the programming languages used for development.

Of course, improving existing features is extremely important, and there are many new features to be added. As a major development plan this year, we aim to develop features to effectively attach GlueSQL to NoSQL databases with their own planners and execution layers. The GlueSQL query planner, currently at a basic level, will see significant changes this year. With the expansion of this planner, not only NoSQL databases but also other SQL databases could be supported without sacrificing performance using GlueSQL.

The synergy that arises from the combination of different databases is a significant bonus in this process.

The Journey of the GlueSQL Team

The GlueSQL project was first conceived in the fall of 2019, and since then we have been developing it continuously. Personally, I have created various products in a variety of environments, including game development, backend server, and frontend development over the past decade. The experience gained through this process was a major motivation to start the GlueSQL project.

To put it grandly, the inconveniences felt while using different databases in various environments were a major motivation, wouldn't you say?

The start was actually a bit simple. Around 2019, I was mainly doing web front-end development. However, the lack of a structured database for state management and internal data processing made it very uncomfortable, especially since I couldn't use SQL databases and the like. So I started to lightly create an SQL database that could run on a web browser. Also, I wanted to use Rust, but after failing to introduce it at the company I was working for at the time, I decided to use it in my own project.

But as I started developing, my dreams grew significantly. Beyond a SQL database that simply operates on a web browser, I started envisioning a database that fits the name "Glue", one that can easily be ported to various environments, and I continue that journey to this day.

Whether I took the database project too lightly, or because the features I wanted kept increasing, the content to be developed kept expanding. As a result, I ended up investing full time in the GlueSQL project development for over three years. For a year in between, I even juggled full-time software engineering work alongside GlueSQL development. Currently, I'm back to developing the GlueSQL project full time, alongside various part-time contributors.

Now, we're getting very close to the starting point of the picture I wanted to create through GlueSQL, and thankfully, with contributors joining me, I am not alone.

The Sustainability and Business Aspect of GlueSQL

I believe that what we create through GlueSQL will make a great contribution to the world and make many software engineers happy. This gives me immense strength to continue developing even in difficult situations. However, we cannot accomplish everything with pure passion alone. As much as the GlueSQL project can make a significant contribution, I also see it as holding great business value.

The business strategy of GlueSQL may be somewhat different from other databases. We distribute the project itself as open source under the Apache-2.0 license, so that anyone can use it fully, and we do not consider pricing methods such as restricting features to the storages we support. In fact, if there is any player who can do it better, there's no way to prevent them from taking the GlueSQL project and making it their own.

But we believe that GlueSQL has great potential in this regard. Anyone can participate and they are free to distribute their own storage in the way they want, whether it's open source, private, or commercial. This eliminates the need to create something to replace the GlueSQL project. We aim to prevent the need to recreate the wheel that we provide using GlueSQL.

Moreover, our GlueSQL team seeks to continually expand our group of developers and companies working with us. During this development process, while they can certainly implement everything on their own, there is also no reason not to collaborate with our GlueSQL Team, especially for databases like NoSQL that have their own planners and execution layers. If you have a REST API and want to enhance convenience through SQL support, you can do it yourself or you can collaborate with us.

In addition, for some storages, we can also participate as players in the same position as other custom storage developers. We plan to expand the GlueSQL ecosystem in various ways, such as technical support and storage development.

We are finally ready to provide GlueSQL to users at the production level. We are accelerating the development of GlueSQL. If you are a company interested in storage development like SQL support, or if you resonate with our vision and want to join us, please contact us at taehoon@gluesql.com.

Conclusion

The continued emergence of new databases is driven by the demand for diverse and specialized databases, such as those optimized for Large Language Models (LLMs) and databases catering to unique requirements, like embedded databases, OLAP, OLTP, and time-series data processing. However, developing a new database from scratch is a significant undertaking, requiring extensive work, which often results in high costs.

GlueSQL presents a solution to this challenge by providing a unified query interface that can be ported across various environments, from key-value databases, NoSQL databases, log files, to REST APIs. It allows anyone to create custom storages, reducing the need for developers to build entirely new databases and to learn different usage methods for each database. Instead, they can focus on implementing their business logic using the same interface.

From a user perspective, GlueSQL offers the convenience of a unified query interface, easing the burden of learning different interfaces for each database. This simplification of interface use can also extend to AI, potentially enhancing the efficiency of AI automation.

GlueSQL's development plan includes significant enhancements to its query planner and aims to enable effective attachment of GlueSQL to NoSQL databases. The synergy of combining different databases is a valuable bonus in this process.

Since its inception in the fall of 2019, the GlueSQL team has continuously developed the project, driven by the desire to mitigate the inconveniences encountered while using different databases in various environments. The journey has been a rewarding one, with the GlueSQL project now at a point where it closely resembles the envisioned product.

GlueSQL, distributed under the Apache-2.0 license, is free for anyone to use and adapt. While the GlueSQL team welcomes collaboration with other developers and companies, they also see significant potential for the project as a business venture. The team is working to expand the GlueSQL ecosystem through a variety of initiatives, including technical support and storage development.

With GlueSQL now sufficiently prepared for practical applications, the team invites companies interested in storage development or those who share their vision to join them in their journey of revolutionizing database development.

· 10 min read
Taehoon Moon

Introduction: GlueSQL and Test-Driven Documentation

Recently, the GlueSQL project reached a significant milestone with the release of version 0.14. This new version brings a host of fresh features to the table, yet one of the most notable changes is in the realm of documentation. For the first time, we're proud to announce the launch of our official documentation website. Interested readers can explore the full range of user manuals at https://gluesql.org/docs.

Prior to this update, the only way to navigate GlueSQL was by manually inspecting the test code within the test suite. With the recent release, however, a comprehensive user manual has been made public to facilitate a more user-friendly experience. We hope that this new addition will prove beneficial to a broad spectrum of users.

The task of compiling an entire database manual in one go was daunting due to the sheer volume of content required. Surprisingly, this process turned out to be smoother than initially anticipated, largely due to the invaluable aid of ChatGPT, which was instrumental in automating much of the document creation. Specifically, around 80% of the SQL Syntax section was generated using this tool.

This remarkable feat was only possible due to the solid foundation of test codes previously established in GlueSQL. In this article, we'll share how we managed to leverage ChatGPT in such a unique way. Based on our recent experience of crafting documents grounded in testing, we've begun to consider the possibility of entirely automating document creation, save for the initial stages.

Along with sharing our journey so far, we will also reveal our plans for future test-based automation of documentation within GlueSQL.

Test Codes and Documentation

The GlueSQL project has placed a significant emphasis on writing test codes. This might be a given for a database project; however, the thoroughness of our approach is evident from our line coverage of nearly 99% for core codes. While we devoted considerable effort to creating these test codes, our primary focus has always been on a different aspect: ensuring that anyone can quickly grasp the content of the tests and easily add new ones.

The intent here is to empower newcomers to GlueSQL to understand the functionality of the software solely by examining integration tests, even in the absence of a user manual.

The integration tests for GlueSQL can be found in the test-suite workspace. For example, here's an excerpt of the test code for the INSERT statement:

test_case!(insert, async move {
run!(
"
CREATE TABLE Test (
id INTEGER DEFAULT 1,
num INTEGER NULL,
name TEXT NOT NULL,
);"
);

test! {
name: "basic insert - single item",
sql: "INSERT INTO Test (id, num, name) VALUES (1, 2, 'Hi boo');",
expected: Ok(Payload::Insert(1))
};


test! {
sql: "INSERT INTO Test VALUES(17, 30, 'Sullivan');",
expected: Ok(Payload::Insert(1))
};

test! {
sql: "INSERT INTO Test (num, name) VALUES (28, 'Wazowski');",
expected: Ok(Payload::Insert(1))
};

test! {
sql: "SELECT * FROM Test;",
expected: Ok(select!(
id | num | name;
I64 | I64 | Str;
1 2 "Hi boo".to_owned();
3 9 "Kitty!".to_owned();
2 7 "Monsters".to_owned();
17 30 "Sullivan".to_owned();
1 28 "Wazowski".to_owned()
))
};

// ...
});

Despite being written in Rust, these test cases are designed to be comprehensible, even to those unfamiliar with the language. Each test is a complete scenario from start to finish, and the results of each operation are readily observable.

Given that identifying results from SELECT operations in the form of Rust enums and structs can be challenging, we actively utilized macros such as select! and select_with_null!. We've composed the test cases to demonstrate that the INSERT statement can handle a wide range of cases, including specifying all columns, omitting some, or omitting all.

test! {
sql: "INSERT INTO Test (id, num) VALUES (1, 10);",
expected: Err(InsertError::LackOfRequiredColumn("name".to_owned()).into())
};

The tests also include scenarios for expected faulty inputs, indicating the error returns in these situations.

By organizing the tests in this manner, we aim to make it easy for anyone to read and write tests. Our goal was for these tests to serve as "documentation" for GlueSQL contributors. At the time we were writing these tests, we didn't anticipate that they could actually become documentation themselves. But we've come to realize that they have extraordinary potential.

Leveraging ChatGPT

When we first embarked on writing the User Manual, we were overwhelmed by the sheer volume of content we had to generate. Around the same time, ChatGPT was gaining prominence, and we thought it might be worth trying out, if only to lighten our load slightly.

To our surprise, ChatGPT exceeded our expectations. If the test codes were well written, it was capable of automatically crafting an exceptional document based on them, capturing all essential details.

After several trials and errors, we settled on the following prompt for document generation. While it's still a challenge to use the same prompt for all documentation, we made minor modifications to suit different situations:

I'm creating an SQL database documentation website, and I'd like you to help me with one of the pages that introduces the SQL syntax for GlueSQL.

1. Please provide the response content in the "markdown" format, so I can copy and paste it directly. Keep this constraint in mind while writing.
2. Regardless of the language I use, I need the content written in English.
3. I will provide some test case code written in the Rust language, which contains SQL examples. Please write the documentation based on these examples, but feel free to change the table names, column names, and data types as needed. Don't include any Rust related content or text in the response. all the response code example should be in plain SQL.
4. GlueSQL does not have the VARCHAR type. If you want to use that, please use TEXT instead. You don't need to mention this in the response.
5. Wrap the entire response text using <pre> and </pre> tags so I can copy all the content easily.

Now, I'd like you to write the following request:
SQL Statement - "INSERT"

Here's an example test code you can refer to:

test_case!(insert, async move {
run!(...

Generally, we used the template above, and copied and pasted the test code from our existing test-suite. We leveraged this method to harness our many tests to assist in the creation of the user manual. In the next section, we'll showcase a sample of the documentation generated in this manner. It's quite impressive.

Success Case: Automated User Manual of GlueSQL

Thanks to ChatGPT, the resulting INSERT document page can be viewed at the following link. It's important to note that we used ChatGPT 4 for this task. Version 3.5 wasn't quite up to the task, and using version 4 was the minimum requirement.

https://gluesql.org/docs/dev/sql-syntax/statements/data-manipulation/insert

INSERT Statement

The results were quite impressive. ChatGPT neatly categorized the test cases, explained the syntax, outlined constraints, and provided appropriate examples. It didn't stop there; it also skillfully recognized error test cases and incorporated them into the documentation, as shown below.

INSERT Statement

Isn't it amazing?

Future Plans: Fully Automating Documentation Generation

While the current documentation is far from perfect and there are many aspects that can be improved, we see great potential in this approach. We believe it's entirely possible to automate the process of writing this kind of document, and writing in general.

In the past, documents like user manuals required a great deal of effort to maintain once they were written. If a document contained real code examples, verifying that the code still worked was often a tedious task. With the ability to automatically generate documentation as we have done here, these issues are no longer problematic.

Previously, you would have to write tests and then also document them separately. If you had to support multiple languages, that would be an additional task. With a tool like ChatGPT, you can automate all of this. All a developer has to do is write the tests. This alone can be sufficient. You can generate documents automatically based on the tests. Eventually, we can even support automatically translating these documents into multiple languages.

The GlueSQL project repository is currently hosted on GitHub and makes good use of various GitHub Actions. We envision a GitHub Action that automatically regenerates a document corresponding to a test when a user modifies the test and raises a Pull Request. Another GitHub Action could automatically translate updated documents into supported languages and create new Pull Requests. The possibilities are truly endless.

Not only will this help with document generation, but it will also provide clear guidelines for writing better test code. If we can automatically generate documents based on written tests, the quality of those documents can serve as an indicator of the quality of the tests themselves. This means that a document automation tool can play the role of a good reviewer for tests. It can greatly reduce the time and effort required for painstakingly reviewing the quality of each test. Developers can also write tests without pressure, evaluate their test code by looking at the generated document, and improve it.

Furthermore, multi-language support becomes a breeze. In my personal experience as a software engineer over the past decade, developing various products such as games, web services, and applications, I often needed to support multiple languages. Each time, there was no definite solution. The optimal approach varied depending on the situation, and there were many things to consider when entrusting translations, such as effectively communicating the context of the target service to the translator. Moreover, regularly updating content and having it retranslated into various languages was a very tedious process. While I tried to automate as much as possible by creating various tools, I was never fully satisfied. I believe ChatGPT can completely solve these issues. If there is a need to provide project-specific context, all you need to do is prepare a prompt in advance. Instead of having to rely on and wait for professional translators, we can now entrust this task to ChatGPT, and we only need a few people to review the translated content.

We are nearing a world where documentation is no longer a burden for developers.

Conclusion: The Value of Test-Driven Documentation

The use of ChatGPT to generate documentation has proven a significant step forward in the GlueSQL user manual creation process. Through test-driven documentation, we've managed to automate a substantial part of the manual creation process, saving time and effort, and increasing accuracy.

Moreover, this process has unveiled a new potential for documentation: the possibility of fully automating document generation. We've seen that quality tests can become quality documentation with the help of AI, leading to more efficient workflows and possibly better test code as a result.

The journey doesn't stop here. We envision leveraging this capability further to auto-translate our documents into multiple languages, making our product more accessible to a global audience.

As we progress, we hope that our experience can inspire other developers to explore and embrace the benefits of AI-generated, test-driven documentation. It's not just about saving time—it's about improving the way we work, communicate, and share knowledge.

· 11 min read
Taehoon Moon

Introduction

The divide between SQL and NoSQL databases has often presented challenges in database management. GlueSQL, a unique database maker library, aims to blur this boundary, providing a versatile tool for handling these two distinct types of databases.

In this article, we explore how GlueSQL navigates the features of SQL and NoSQL databases, offering an integrated solution that promotes flexibility and efficiency. With its ability to unify disparate database types, GlueSQL heralds a new age of adaptable database creation and management.

The Interface Perspective: SQL & AST Builder

When we talk about SQL databases, it's almost a given that they support SQL - the standard query language. Although there are slight variations between databases, the convenience of using a similar SQL language across multiple databases cannot be overstated. However, from a software engineer's perspective, there's room for improvement. In most software development scenarios, a specific programming language is used. SQL is a separate language, which can cause friction when integrating it into your software. As a result, rather than using raw SQL, many developers employ query builders or ORMs to manipulate SQL conveniently using their preferred programming language. Although it's not efficient to generate SQL using a query builder and then parse it again in the database, it's a practical and effective choice.

On the other hand, NoSQL databases offer different mechanisms. Some of them have their own language similar to SQL, but most provide an interface library developed specifically for each programming language. While SQL databases rely on external query builder libraries to provide an interface for each programming language, NoSQL databases mostly develop and offer these libraries themselves. If we discount the convenience of SQL language, this is one of the major factors that make NoSQL databases more comfortable to use. Since query builder libraries supporting SQL databases often cater to multiple SQL databases, they are limited in fully supporting unique features of each database. NoSQL databases, on the other hand, can freely manage their interface libraries without these restrictions.

Providing a query interface for each programming language is not a fundamental difference between SQL and NoSQL, but we generally accept it implicitly.

Let's see what happens if we break down this boundary, using GlueSQL as an example. As you can see from the SQL postfix, GlueSQL supports SQL and can be classified as an SQL database.

CREATE TABLE Glue (id INTEGER, name TEXT);

INSERT INTO Glue VALUES (1, "hello"), (2, "gluesql");

SELECT * FROM Glue WHERE id = 1;

However, GlueSQL also supports its own query builder, like a NoSQL database. +(Currently, only Rust is supported, but we're working on adding support for other languages.)

table("Glue")
.create_table()
.add_column("id INTEGER")
.add_column("name TEXT")
.execute(glue)

table("Glue")
.insert()
.values(vec![
vec![num(1), text("hello")],
vec![num(2), text("gluesql")],
])
.execute(glue)
.await;

table("Glue")
.select()
.filter(col("id").eq(1))
.execute(glue)
.await;

Let's reconsider the implicit distinction between SQL and NoSQL. GlueSQL indeed supports SQL, but it also officially develops and offers its own query builder. This query builder is not a secondary tool for SQL. While most SQL query builder libraries ultimately generate SQL strings, GlueSQL's builder directly creates an AST (Abstract Structure Tree) that is used for execution within GlueSQL. Hence, we call it the AST Builder. This means SQL and the AST Builder are two equally supported interfaces in GlueSQL.

This also offers an additional advantage:

table("Glue")
.select()
// 1.
.filter(col("id").eq(1))
// 2.
.filter("id = 1")
.execute(glue)
.await;

Because GlueSQL already supports SQL, not only can you use the custom interface in the AST Builder, but you can also use familiar SQL syntax in part. Whether you use col("id").eq(1) or "id = 1", you can use it in the way you prefer. The AST Builder interface, although initially unfamiliar, allows a gradual migration similar to writing SQL for your convenience.

Thus, we've dismantled one of the implicit distinctions between SQL and NoSQL. However, it's more of an implicit differentiation than a fundamental one. There are more significant design differences that we'll explore next.

Structured & Unstructured Data

In this section, we'll discuss how SQL and NoSQL handle data. SQL generally deals with structured data, and recently, it's been made to support semi-structured data as well. On the other hand, NoSQL supports schemaless, unstructured data. Then, we'll explain in detail how GlueSQL handles these two types of data. The last part of this section will provide a segue into the next section where we'll discuss the decomposition of database functions.

When talking about SQL databases, one aspect is usually considered together: SQL databases have a defined schema.

CREATE TABLE Foo (
id INTEGER,
name TEXT,
rate FLOAT NULL
);

However, these days, SQL databases tend to support semi-structured data types, such as LIST or JSON. But, supporting completely schemaless, unstructured data is a different matter. SQL databases typically require a minimum schema.

What about NoSQL databases? As NoSQL databases vary significantly, we can't make definitive statements. But let's consider a typical document database like MongoDB. Unlike SQL databases, it doesn't enforce a schema. Essentially, you can insert any form of data directly. Often, NoSQL databases support schemaless data, but they lack features that enforce a schema like SQL. They generally support structure via validation methods, rather than structured access.

Is there no choice but to distinguish between structured data and unstructured, schemaless data so clearly? GlueSQL is being developed with the goal of being adaptable in various environments. Being forced to choose regarding this schema constraint was quite inconvenient. We started pondering if we couldn't benefit from both aspects - supporting both schema and schemaless data simultaneously, and we eventually found the answer. Let's look at how GlueSQL currently solves this issue through familiar SQL examples.

CREATE TABLE Names (id INTEGER, name TEXT);
INSERT INTO Names VALUES (1, 'glue'), (2, 'sql');

You can create a regular table with a schema like this. But GlueSQL's choice for creating a schemaless table is as follows:

CREATE TABLE Logs;
INSERT INTO Logs VALUES
('{ "id": 1, "value": 30 }'),
('{ "id": 2, "rate": 3.0, "list": [1, 2, 3] }'),
('{ "id": 3, "rate": 5.0, "value": 100 }');

It creates a table without column definitions! If you do this, GlueSQL recognizes the table as schemaless and processes it internally.

SELECT id, rate, list[0] FROM Logs WHERE id = 2;

Although the way to create the table was a bit special, using it isn't much different from the regular SQL SELECT statement. Not only can you differentiate between schema and schemaless when creating tables, but you can also use them interchangeably!

SELECT * FROM Names JOIN Logs ON Names.id = Logs.id;
/*
| id | list | name | rate | value |
|----|---------|------|------|-------|
| 1 | | glue | | 30 |
| 2 |[1, 2, 3]| sql | 3 | |
*/

Here's an example of querying data by INNER JOINing the Names table, which has a schema, and the Logs table, which is schemaless. GlueSQL has resolved this problem by allowing the internal execution layer to handle both vector-type data, for cases where each row has a defined schema, and map-type data for schemaless cases.

Thanks to this, the variety of storage that can be supported through GlueSQL has expanded significantly. If there were previously limitations to supporting NoSQL databases that support schemaless data, that is no longer the case. The reference storage where you can directly experience this schemaless data support is JSON Storage. It offers features that allow you to deal directly with unstructured data like JSON using GlueSQL.

If GlueSQL starts from the perspective of an SQL database and expands, by providing the AST Builder directly, it once blurs the boundary, and by supporting unstructured data simultaneously, it knocks down the boundary once more. How do you like it?

Decomposing Database Functionality: Breaking Down SQL and NoSQL Features

The distinction between SQL and NoSQL is not just about whether they support unstructured data. Of course, there are examples like unstructured data, which is mainly supported only in NoSQL, but in many cases, SQL databases tend to support more diverse and complex queries. NoSQL often gains other advantages in exchange for reducing the range of query support provided by SQL databases.

GlueSQL is ambitious. It has devised a rather interesting method to support all of this through SQL and the AST Builder, with the same interface. When we usually say SQL database, it implicitly assumes that a lot of features have been fully implemented. Create tables by specifying a schema, modify schemas with "alter table", support both clustered and non-clustered indexes, and support transactions. And there's so much more. But the functionality that is naturally supported in SQL databases may not be natural in other environments.

Let's think about JSON Storage. GlueSQL's JSON Storage allows you to handle JSON, JSONL files using SQL and the AST Builder. This JSON Storage does not support atomic operations or transactions. Of course, it would be great if it did, but implementing and executing them would be a significant performance burden. In most cases, when you want to simply browse and handle JSONL files, the overhead caused by transactions can be an unnecessary burden. In this case, you want to handle JSON, JSONL files using SQL, but you don't necessarily need transactions.

To meet the requirements of these diverse environments, GlueSQL has separated the functionality of what we usually call an SQL database into multiple independent interfaces. +Store, StoreMut, AlterTable, Transaction, .. +These are just a few of the various storage interfaces that GlueSQL currently supports. +The way it works can be summarized like this: +If you implement Store, you can use SELECT. +And if you implement both Store and StoreMut, you can support quite a number of basic SQL statements including SELECT. +You can manage tables with CREATE TABLE, DROP TABLE, and handle data using INSERT, UPDATE, DELETE statements. +If you only need to retrieve data, you only need to implement Store. +If you want to support the ALTER TABLE statement, you can additionally implement the AlterTable interface. +The Transaction interface works the same way. +The interesting part is that, except for Store and StoreMut, all other storage interfaces can be implemented independently. GlueSQL allows you to choose and implement only the features you need. +And it's not just about providing interfaces. It also provides integration tests suitable for each situation to verify what you have implemented. You just need to implement the interface and import the corresponding test case for verification.

In addition to supporting both structured and unstructured data simultaneously, GlueSQL provides the ability to divide the functionality of a database into multiple independent features and selectively implement them. This allows GlueSQL to be ported to a wide variety of environments without any burden.

Conclusion

GlueSQL, while serving as a database that provides its own reference storage, is fundamentally a library designed to simplify the creation of databases. One of the substantial challenges GlueSQL had to overcome in order to support a diverse array of environments was to address the distinctive features that separate conventional SQL databases from NoSQL databases. GlueSQL achieved this through several innovative approaches, managing to support both categories simultaneously despite their significantly different characteristics.

It offers support for SQL alongside an AST Builder, and accommodates both structured and unstructured data. Additionally, it decomposes database functionalities into multiple independent features, allowing each environment to selectively implement the functionalities it requires.

These unique attributes enable GlueSQL to live up to its 'Glue' prefix by facilitating effortless porting across various environments. While we have been developing it for several years, there is still much ground to cover. However, the fact that we are now able to introduce it publicly attests to our successful technological validation and completion of a demonstrable level of implementation.

Through GlueSQL, we hope to provide developers with a unified query interface that can be customized according to their needs, thereby enabling them to produce efficient products more effortlessly. There's a promising future ahead for GlueSQL, and we look forward to its contributions to the technology community.

· 11 min read
Taehoon Moon

We now provide an official documentation website at https://gluesql.org/docs

🚀 Features

🍀 Schemaless data support

GlueSQL now supports creating tables without a schema, allowing for both structured and unstructured data to be stored in the same table. +To create a schemaless table, simply run CREATE TABLE without specifying any columns. For more information on querying schemaless data, please refer to the following link: querying schemaless data

CREATE TABLE Bar;

To insert values,

INSERT INTO Bar VALUES
('{ "name": "ast", "value": 30 }'),
('{ "name": "glue", "rate": 3.0, "list": [1, 2, 3] }'),

Then, selecting values from schemaless table is simple.

SELECT name, rate, list[0] FROM Bar WHERE name = 'glue';

e.g.

CREATE TABLE Names (id INTEGER, name TEXT);
INSERT INTO Names VALUES (1, 'glue'), (2, 'sql');

CREATE TABLE Logs;
INSERT INTO Logs VALUES
('{ "id": 1, "value": 30 }'),
('{ "id": 2, "rate": 3.0, "list": [1, 2, 3] }'),
('{ "id": 3, "rate": 5.0, "value": 100 }');

SELECT * FROM Names JOIN Logs ON Names.id = Logs.id;
/*
| id | list | name | rate | value |
|----|---------|------|------|-------|
| 1 | | glue | | 30 |
| 2 |[1, 2, 3]| sql | 3 | |
*/

🍀 IndexedDB & WebStorage supports in JavaScript package

GlueSQL supports handling in-memory, localStorage, sessionStorage, and even IndexedDB using the same SQL syntax. All you need to know is how to specify the ENGINE when creating a table.

e.g.

CREATE TABLE Mem (mid INTEGER) ENGINE = memory;
CREATE TABLE Loc (lid INTEGER) ENGINE = localStorage;
CREATE TABLE Ses (sid INTEGER) ENGINE = sessionStorage;
CREATE TABLE Idb (iid INTEGER) ENGINE = indexedDB;

SELECT
mid, lid, sid, iid
FROM Mem
JOIN Loc
JOIN Ses
JOIN Idb;

🍀 Data Types - UINT32, UINT64, UINT128, POINT and FLOAT32

🍀 Functions - APPEND, PREPEND, RAND, FIND_IDX, INITCAP and CALC_DISTANCE

🍀 Store traits

User-level custom function

By implementing both the CustomFunction and CustomFunctionMut traits, users can create, use, and delete user-level custom functions. Although GlueSQL plans to continuously add various functions, users may still find them insufficient. In such cases, users can create their own user-level custom functions to supplement the built-in functions. Additionally, if there are repetitive business logic codes, they can be stored as custom functions. +e.g.

CREATE FUNCTION ADD_ONE (n INT, x INT DEFAULT 1) RETURN n + x;

SELECT ADD_ONE(10) AS test;

DROP FUNCTION ADD_ONE;

Metadata

The Metadata trait is an optional implementation for providing additional metadata support in GlueSQL. GlueSQL does not enforce any specific metadata implementation, allowing custom storage developers to decide which type of metadata, such as create time, modify time, etc., they want to provide.

🍀 Storages

JSON Storage

Composite Storage

  • Add CompositeStorage which bundles multiple storages @panarch (#1068)

IndexedDB Storage

Web Storage

  • Add WebStorage - support localStorage \& sessionStorage for web browsers @panarch (#1050)

🍀 Other new features

🌊 Interface Changes

  • Remove Store trait related cfg features, @panarch (#1091)
  • Refactor CreateTable.columns from Vec<ColumnDef> to Option<Vec<ColumnDef>> @devgony (#1086)
  • Remove MutResult @panarch (#1073)
  • Update all store mut trait methods to take \&mut self @panarch (#1072)
  • Change StoreMut interface to use \&mut self, not to take ownership @panarch (#1071)
  • Modify default ColumnOption from NOT NULL to NULL @devgony (#997)

🌟 Improvements

🌳 Documentation

We now provide an official documentation website at https://gluesql.org/docs

Docs - setup

📋 Tests

🐛 Bug Fixes

  • Fix docusaurus pages/index broken link @panarch (#1214)
  • Fix docs/ Discord GlueSQL channel invite link address @panarch (#1213)
  • Fix InvalidJsonString error message replacing payload to fileName @devgony (#1185)
  • Fix TryFrom Value::Str to u128 not to use parse_uuid @ChobobDev (#1134)
  • Fix column alias with identifer for TableFactor::Derived @ding-young (#1119)
  • Pass data even when deleted_by is not present @ever0de (#1117)
  • Fix MemoryStorage \& WebStorage primary key support @panarch (#1115)
  • Fix plan::validate to handle CTAS and ITAS adding unit test @devgony (#1074)
  • Fix test-suite tester functions to show (found, expected) shape @panarch (#1028)
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/blog/release-v0.14/index.html b/docs/0.16.0/blog/release-v0.14/index.html new file mode 100644 index 00000000..d3442bd8 --- /dev/null +++ b/docs/0.16.0/blog/release-v0.14/index.html @@ -0,0 +1,19 @@ + + + + + +Release v0.14 | GlueSQL + + + + + +
+

Release v0.14

· 11 min read
Taehoon Moon

We now provide an official documentation website at https://gluesql.org/docs

🚀 Features

🍀 Schemaless data support

GlueSQL now supports creating tables without a schema, allowing for both structured and unstructured data to be stored in the same table. +To create a schemaless table, simply run CREATE TABLE without specifying any columns. For more information on querying schemaless data, please refer to the following link: querying schemaless data

CREATE TABLE Bar;

To insert values,

INSERT INTO Bar VALUES
('{ "name": "ast", "value": 30 }'),
('{ "name": "glue", "rate": 3.0, "list": [1, 2, 3] }'),

Then, selecting values from schemaless table is simple.

SELECT name, rate, list[0] FROM Bar WHERE name = 'glue';

e.g.

CREATE TABLE Names (id INTEGER, name TEXT);
INSERT INTO Names VALUES (1, 'glue'), (2, 'sql');

CREATE TABLE Logs;
INSERT INTO Logs VALUES
('{ "id": 1, "value": 30 }'),
('{ "id": 2, "rate": 3.0, "list": [1, 2, 3] }'),
('{ "id": 3, "rate": 5.0, "value": 100 }');

SELECT * FROM Names JOIN Logs ON Names.id = Logs.id;
/*
| id | list | name | rate | value |
|----|---------|------|------|-------|
| 1 | | glue | | 30 |
| 2 |[1, 2, 3]| sql | 3 | |
*/

🍀 IndexedDB & WebStorage supports in JavaScript package

GlueSQL supports handling in-memory, localStorage, sessionStorage, and even IndexedDB using the same SQL syntax. All you need to know is how to specify the ENGINE when creating a table.

e.g.

CREATE TABLE Mem (mid INTEGER) ENGINE = memory;
CREATE TABLE Loc (lid INTEGER) ENGINE = localStorage;
CREATE TABLE Ses (sid INTEGER) ENGINE = sessionStorage;
CREATE TABLE Idb (iid INTEGER) ENGINE = indexedDB;

SELECT
mid, lid, sid, iid
FROM Mem
JOIN Loc
JOIN Ses
JOIN Idb;

🍀 Data Types - UINT32, UINT64, UINT128, POINT and FLOAT32

🍀 Functions - APPEND, PREPEND, RAND, FIND_IDX, INITCAP and CALC_DISTANCE

🍀 Store traits

User-level custom function

By implementing both the CustomFunction and CustomFunctionMut traits, users can create, use, and delete user-level custom functions. Although GlueSQL plans to continuously add various functions, users may still find them insufficient. In such cases, users can create their own user-level custom functions to supplement the built-in functions. Additionally, if there are repetitive business logic codes, they can be stored as custom functions. +e.g.

CREATE FUNCTION ADD_ONE (n INT, x INT DEFAULT 1) RETURN n + x;

SELECT ADD_ONE(10) AS test;

DROP FUNCTION ADD_ONE;

Metadata

The Metadata trait is an optional implementation for providing additional metadata support in GlueSQL. GlueSQL does not enforce any specific metadata implementation, allowing custom storage developers to decide which type of metadata, such as create time, modify time, etc., they want to provide.

🍀 Storages

JSON Storage

Composite Storage

  • Add CompositeStorage which bundles multiple storages @panarch (#1068)

IndexedDB Storage

Web Storage

  • Add WebStorage - support localStorage \& sessionStorage for web browsers @panarch (#1050)

🍀 Other new features

🌊 Interface Changes

  • Remove Store trait related cfg features, @panarch (#1091)
  • Refactor CreateTable.columns from Vec<ColumnDef> to Option<Vec<ColumnDef>> @devgony (#1086)
  • Remove MutResult @panarch (#1073)
  • Update all store mut trait methods to take \&mut self @panarch (#1072)
  • Change StoreMut interface to use \&mut self, not to take ownership @panarch (#1071)
  • Modify default ColumnOption from NOT NULL to NULL @devgony (#997)

🌟 Improvements

🌳 Documentation

We now provide an official documentation website at https://gluesql.org/docs

Docs - setup

📋 Tests

🐛 Bug Fixes

  • Fix docusaurus pages/index broken link @panarch (#1214)
  • Fix docs/ Discord GlueSQL channel invite link address @panarch (#1213)
  • Fix InvalidJsonString error message replacing payload to fileName @devgony (#1185)
  • Fix TryFrom Value::Str to u128 not to use parse_uuid @ChobobDev (#1134)
  • Fix column alias with identifer for TableFactor::Derived @ding-young (#1119)
  • Pass data even when deleted_by is not present @ever0de (#1117)
  • Fix MemoryStorage \& WebStorage primary key support @panarch (#1115)
  • Fix plan::validate to handle CTAS and ITAS adding unit test @devgony (#1074)
  • Fix test-suite tester functions to show (found, expected) shape @panarch (#1028)
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/blog/release-v0.15/index.html b/docs/0.16.0/blog/release-v0.15/index.html new file mode 100644 index 00000000..145127a1 --- /dev/null +++ b/docs/0.16.0/blog/release-v0.15/index.html @@ -0,0 +1,17 @@ + + + + + +Release v0.15 | GlueSQL + + + + + +
+

Release v0.15

· 6 min read
Taehoon Moon

🌊 Breaking Changes

🍀 Python Support

Code Samples

from gluesql import Glue, MemoryStorage
from tabulate import tabulate

db = Glue(MemoryStorage())

sql = """
SELECT
u.name as user,
d.name as device
FROM User u
JOIN Device d ON u.id = d.userId
""".strip().replace(
" ", ""
)

result = db.query(sql)
rows = result[0].get("rows")
print(f"\n[Query]\n{sql}")
print(tabulate(rows, headers="keys", showindex=True, tablefmt="simple_outline"))

🍀 Redis Storage

🍀 CSV Storage

🍀 More operators and functions

🚀 Features

  • feat: implement select iterator utility function @ever0de (#1429)

🌟 Improvements

🐛 Bug Fixes

  • fix: Literal comparison with BinaryOperator @ding-co (#1397)
  • fix: update Key.cmp to compare a type with other type @tgsong827 (#1367)
  • Fix Value::evaluate_cmp_with_literal between Decimal and Literal::Num… @panarch (#1352)
  • Fix spool on tabular off and SelectMap @devgony (#1314)
  • Update auto-assign-action to be triggered on PR open from fork repos @panarch (#1313)
  • Fix Scala Subquery should contain only 1 column @ChobobDev (#1284)
  • Wrap config path by quotes in auto-author-assign.yml @panarch (#1258)
  • Apply word-wrap to docs/ article h1 @panarch (#1230)
  • Fix docusaurus.config.js themeConfig handler @panarch (#1225)

👏 New Contributors

Full Changelog: https://github.com/gluesql/gluesql/compare/v0.14.0...v0.15.0

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/blog/revolutionizing-databases-by-unifying-query-interfaces/index.html b/docs/0.16.0/blog/revolutionizing-databases-by-unifying-query-interfaces/index.html new file mode 100644 index 00000000..7b874b72 --- /dev/null +++ b/docs/0.16.0/blog/revolutionizing-databases-by-unifying-query-interfaces/index.html @@ -0,0 +1,18 @@ + + + + + +GlueSQL - Revolutionizing Databases by Unifying Query Interfaces | GlueSQL + + + + + +
+

GlueSQL - Revolutionizing Databases by Unifying Query Interfaces

· 14 min read
Taehoon Moon

Introduction

GlueSQL is a versatile database project designed for exceptional portability across a broad range of environments, from embedded systems and servers to web and mobile platforms. The core goal is to support diverse storage environments and manage various data types with a standard SQL approach.

Imagine handling files like CSV, JSONL, and Parquet, or transforming key-value or NoSQL databases such as RocksDB, Redis, and MongoDB into SQL-supporting databases—all feasible with GlueSQL. It can also operate with storages supported in web browsers.

GlueSQL's essential feature is providing a management layer for these diverse storage scenarios without requiring data migration. The broader aim is to facilitate portability of GlueSQL to any environment supporting read or read-write operations. This extends to APIs like GitHub, or messengers like Discord or Slack.

GlueSQL supports both structured and unstructured data and is written in Rust for compatibility with various environments. While portability is its core value, the emphasis is on creating an intuitive, comfortable development environment for easy custom storage implementation.

Ultimately, GlueSQL aims to significantly reduce the cost, time, and complexity of developing new databases. By leveraging GlueSQL for the parser, planner, and execution layer, developers can focus on creating specific storage implementations, leading to a more convenient query interface like SQL for many environments.

The Problem: Why Reinvent the Database?

Despite the numerous database implementations that currently exist, the emergence of new databases continues. The primary reason behind this trend is our need for databases for a broad spectrum of distinct purposes. For instance, new databases are surfacing that are specifically optimized for Large Language Models (LLMs) like ChatGPT. The range is wide and diverse, encompassing embedded databases, OLAP for data analysis, OLTP databases optimized for online transactions, databases specialized for time-series data processing, and many more.

With such varied requirements, we find ourselves in constant need of fresh databases. However, constructing a database from scratch is a monumental task. It necessitates defining a query interface for handling the database and implementing a corresponding parser. Moreover, a separate execution layer for running operations must be built. Also, the planning layer, which is responsible for devising execution strategies, is a vital aspect of this process. Let's not forget about the critical storage layer that physically reads and stores the data. In a nutshell, there's a daunting amount of work involved in developing a new database.

Given these circumstances, it's understandable why numerous emerging databases resort to high pricing structures—they need immediate revenue to offset continuous development costs.

But the story doesn't end here. Query interfaces like SQL are indeed useful for serious tasks, but they also provide excellent utility for handling simple log files such as CSV, JSONL, Parquet, and even for utilizing REST APIs for various applications. The issue arises when a complex query interface needs to be provided even for these lighter storage requirements—it necessitates a development process almost identical to building a sophisticated database. Implementing an entire parser and execution layer just to add SQL support to an existing service can seem like an excessive burden.

Whether it's a simple storage environment or a serious task, the key lies in the storage layer, which involves the actual reading and storing of data. So, what if developers focused on implementing these storage mechanisms while the remaining parts could be handled using existing libraries? This is the role that GlueSQL aspires to play.

The Vision of GlueSQL

The GlueSQL project aims to offer a unified query interface for various environments. The goal is to allow anyone to port and use SQL and GlueSQL's proprietary query builder, the AST Builder, in any desired environment. This could range from key-value databases, serious NoSQL databases, log files, and even REST API services. Essentially, if a service supports reading or read-writing data, regardless of the data type, it can readily support a complex query interface via GlueSQL.

Presently, the GlueSQL project itself directly supports a few storage types as reference storages. These include in-memory storage for non-persistent data handling, sled storage, which is a key-value database written in Rust, JSON storage for handling JSON and JSONL files, and a storage that ports SQL to the web browser's IndexedDB. While the GlueSQL Team is primarily developing these, the aim is to allow anyone to create such custom storages for a wide array of purposes, thus enabling them to assemble the database of their choosing.

Imagine using GlueSQL's SQL and AST Builder everywhere, with the simple method of swapping out storages to operate in diverse settings. It could significantly reduce software development costs. Developers wouldn't need to learn the different usage methods for each database. Instead, they could focus solely on implementing business logic using the same interface.

Our vision is to reduce database development costs by 10 times, or even more than 20 times. We aim to gather diverse database creators under the GlueSQL banner, making it the go-to solution for cost-effective database development.

Benefits to Database Users: Unifying Query Interfaces, Streamlining Software Development, and Reducing Costs

From the perspective of the users who engage with databases, there has always been the burden of learning different interfaces to interact with each database. The approach required to work with Redis is different from that necessary for MongoDB. Likewise, handling SQL databases necessitates using SQL. Although SQL databases generally use a common SQL, the SQL they support can considerably vary when examined in detail.

Naturally, there are legitimate reasons for such differences. Each database focuses on different areas, and to cater to specialized functionalities, they incorporate dedicated interface mechanisms. However, not all application development needs to utilize these database-specific core special functionalities.

Let's look at a couple of examples:

Suppose you're developing a back-end application that uses MySQL as the database and Redis for caching. Due to the vast differences in handling SQL databases and Redis, you would have to develop using different methods when storing data.

Here's another scenario: +Imagine you're implementing a data migration pipeline between various databases and log files. Let's say you're transferring Parquet to Redis or MongoDB. In this case, you would need to convert data using different methods for each, all of which would be a cumbersome process.

In both of the above examples, GlueSQL can directly address and solve the issues. It offers the convenience of a uniform query interface to deal with these matters. In certain scenarios, even the construction of a data pipeline can potentially be solved with a single SQL query, thanks to GlueSQL.

Benefits to Database Developers: Drastically Lowering Development Costs and Simplifying the Creation of Purpose-Built Databases

If you want to support SQL in the desired environment, using GlueSQL essentially requires you to implement an interface for Storage. There's no need to support all functionalities from the beginning. You can start lightly, choosing and implementing storage features suitable for the environment you want to create. To facilitate this, GlueSQL also provides a library in the form of a test suite to easily validate the storage you've implemented.

Lowering development costs in this way will enable a broader range of developers to support the GlueSQL query interface. As more developers join, a significant synergy can be generated. Designing a query interface from scratch involves a great deal of work, including planning and supporting the interface for different target programming languages.

However, despite all this hard work, it is not easy to attract database users accustomed to different methods.

Consider that the SQL and AST Builder provided by GlueSQL are already securing numerous users. This eliminates the need for efforts to promote a newly planned query interface. Over the years, many new databases have emphasized compatibility with PostgreSQL or MySQL for similar reasons. As GlueSQL places a strong emphasis on portability in its query interface planning, it allows for more flexible configuration according to the desired situation. Through the AST Builder, it also eliminates the cost of porting to different languages.

For many database developers, using GlueSQL can be an optimal choice, as it can save costs and quickly secure users.

Let me mention one more thing: what's convenient for humans... could be applied to AI as well. Rather than making AI write automation code using different databases, providing a common query interface can be much more efficient.

The Future with GlueSQL

GlueSQL has been and will continue to improve and develop new features to enable portability in various environments. Thanks to the schemaless data support added last year, it is now possible to handle both structured data with schema and unstructured data like JSON simultaneously. This has significantly increased the range of storage environments that can be supported.

One of the key features added last year was the AST Builder. This feature allowed us to escape the confines of SQL and provide an interface for comfortably handling data in the programming languages used for development.

Of course, improving existing features is extremely important, and there are many new features to be added. As a major development plan this year, we aim to develop features to effectively attach GlueSQL to NoSQL databases with their own planners and execution layers. The GlueSQL query planner, currently at a basic level, will see significant changes this year. With the expansion of this planner, not only NoSQL databases but also other SQL databases could be supported without sacrificing performance using GlueSQL.

The synergy that arises from the combination of different databases is a significant bonus in this process.

The Journey of the GlueSQL Team

The GlueSQL project was first conceived in the fall of 2019, and since then we have been developing it continuously. Personally, I have created various products in a variety of environments, including game development, backend server, and frontend development over the past decade. The experience gained through this process was a major motivation to start the GlueSQL project.

To put it grandly, the inconveniences felt while using different databases in various environments were a major motivation, wouldn't you say?

The start was actually a bit simple. Around 2019, I was mainly doing web front-end development. However, the lack of a structured database for state management and internal data processing made it very uncomfortable, especially since I couldn't use SQL databases and the like. So I started to lightly create an SQL database that could run on a web browser. Also, I wanted to use Rust, but after failing to introduce it at the company I was working for at the time, I decided to use it in my own project.

But as I started developing, my dreams grew significantly. Beyond a SQL database that simply operates on a web browser, I started envisioning a database that fits the name "Glue", one that can easily be ported to various environments, and I continue that journey to this day.

Whether I took the database project too lightly, or because the features I wanted kept increasing, the content to be developed kept expanding. As a result, I ended up investing full time in the GlueSQL project development for over three years. For a year in between, I even juggled full-time software engineering work alongside GlueSQL development. Currently, I'm back to developing the GlueSQL project full time, alongside various part-time contributors.

Now, we're getting very close to the starting point of the picture I wanted to create through GlueSQL, and thankfully, with contributors joining me, I am not alone.

The Sustainability and Business Aspect of GlueSQL

I believe that what we create through GlueSQL will make a great contribution to the world and make many software engineers happy. This gives me immense strength to continue developing even in difficult situations. However, we cannot accomplish everything with pure passion alone. As much as the GlueSQL project can make a significant contribution, I also see it as holding great business value.

The business strategy of GlueSQL may be somewhat different from other databases. We distribute the project itself as open source under the Apache-2.0 license, so that anyone can use it fully, and we do not consider pricing methods such as restricting features to the storages we support. In fact, if there is any player who can do it better, there's no way to prevent them from taking the GlueSQL project and making it their own.

But we believe that GlueSQL has great potential in this regard. Anyone can participate and they are free to distribute their own storage in the way they want, whether it's open source, private, or commercial. This eliminates the need to create something to replace the GlueSQL project. We aim to prevent the need to recreate the wheel that we provide using GlueSQL.

Moreover, our GlueSQL team seeks to continually expand our group of developers and companies working with us. During this development process, while they can certainly implement everything on their own, there is also no reason not to collaborate with our GlueSQL Team, especially for databases like NoSQL that have their own planners and execution layers. If you have a REST API and want to enhance convenience through SQL support, you can do it yourself or you can collaborate with us.

In addition, for some storages, we can also participate as players in the same position as other custom storage developers. We plan to expand the GlueSQL ecosystem in various ways, such as technical support and storage development.

We are finally ready to provide GlueSQL to users at the production level. We are accelerating the development of GlueSQL. If you are a company interested in storage development like SQL support, or if you resonate with our vision and want to join us, please contact us at taehoon@gluesql.com.

Conclusion

The continued emergence of new databases is driven by the demand for diverse and specialized databases, such as those optimized for Large Language Models (LLMs) and databases catering to unique requirements, like embedded databases, OLAP, OLTP, and time-series data processing. However, developing a new database from scratch is a significant undertaking, requiring extensive work, which often results in high costs.

GlueSQL presents a solution to this challenge by providing a unified query interface that can be ported across various environments, from key-value databases, NoSQL databases, log files, to REST APIs. It allows anyone to create custom storages, reducing the need for developers to build entirely new databases and to learn different usage methods for each database. Instead, they can focus on implementing their business logic using the same interface.

From a user perspective, GlueSQL offers the convenience of a unified query interface, easing the burden of learning different interfaces for each database. This simplification of interface use can also extend to AI, potentially enhancing the efficiency of AI automation.

GlueSQL's development plan includes significant enhancements to its query planner and aims to enable effective attachment of GlueSQL to NoSQL databases. The synergy of combining different databases is a valuable bonus in this process.

Since its inception in the fall of 2019, the GlueSQL team has continuously developed the project, driven by the desire to mitigate the inconveniences encountered while using different databases in various environments. The journey has been a rewarding one, with the GlueSQL project now at a point where it closely resembles the envisioned product.

GlueSQL, distributed under the Apache-2.0 license, is free for anyone to use and adapt. While the GlueSQL team welcomes collaboration with other developers and companies, they also see significant potential for the project as a business venture. The team is working to expand the GlueSQL ecosystem through a variety of initiatives, including technical support and storage development.

With GlueSQL now sufficiently prepared for practical applications, the team invites companies interested in storage development or those who share their vision to join them in their journey of revolutionizing database development.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/blog/rss.xml b/docs/0.16.0/blog/rss.xml new file mode 100644 index 00000000..1862ee6c --- /dev/null +++ b/docs/0.16.0/blog/rss.xml @@ -0,0 +1,84 @@ + + + + GlueSQL Blog + https://gluesql.org/docs/0.16.0/blog + GlueSQL Blog + Sat, 18 Nov 2023 00:00:00 GMT + https://validator.w3.org/feed/docs/rss2.html + https://github.com/jpmonette/feed + en + + <![CDATA[Release v0.15]]> + https://gluesql.org/docs/0.16.0/blog/release-v0.15 + https://gluesql.org/docs/0.16.0/blog/release-v0.15 + Sat, 18 Nov 2023 00:00:00 GMT + + 🌊 Breaking Changes

🍀 Python Support

Code Samples

from gluesql import Glue, MemoryStorage
from tabulate import tabulate

db = Glue(MemoryStorage())

sql = """
SELECT
u.name as user,
d.name as device
FROM User u
JOIN Device d ON u.id = d.userId
""".strip().replace(
" ", ""
)

result = db.query(sql)
rows = result[0].get("rows")
print(f"\n[Query]\n{sql}")
print(tabulate(rows, headers="keys", showindex=True, tablefmt="simple_outline"))

🍀 Redis Storage

🍀 CSV Storage

🍀 More operators and functions

🚀 Features

  • feat: implement select iterator utility function @ever0de (#1429)

🌟 Improvements

🐛 Bug Fixes

  • fix: Literal comparison with BinaryOperator @ding-co (#1397)
  • fix: update Key.cmp to compare a type with other type @tgsong827 (#1367)
  • Fix Value::evaluate_cmp_with_literal between Decimal and Literal::Num… @panarch (#1352)
  • Fix spool on tabular off and SelectMap @devgony (#1314)
  • Update auto-assign-action to be triggered on PR open from fork repos @panarch (#1313)
  • Fix Scala Subquery should contain only 1 column @ChobobDev (#1284)
  • Wrap config path by quotes in auto-author-assign.yml @panarch (#1258)
  • Apply word-wrap to docs/ article h1 @panarch (#1230)
  • Fix docusaurus.config.js themeConfig handler @panarch (#1225)

👏 New Contributors

Full Changelog: https://github.com/gluesql/gluesql/compare/v0.14.0...v0.15.0

]]>
+ v0.15 + release-note +
+ + <![CDATA[GlueSQL - Revolutionizing Databases by Unifying Query Interfaces]]> + https://gluesql.org/docs/0.16.0/blog/revolutionizing-databases-by-unifying-query-interfaces + https://gluesql.org/docs/0.16.0/blog/revolutionizing-databases-by-unifying-query-interfaces + Tue, 30 May 2023 00:00:00 GMT + + Introduction

GlueSQL is a versatile database project designed for exceptional portability across a broad range of environments, from embedded systems and servers to web and mobile platforms. The core goal is to support diverse storage environments and manage various data types with a standard SQL approach.

Imagine handling files like CSV, JSONL, and Parquet, or transforming key-value or NoSQL databases such as RocksDB, Redis, and MongoDB into SQL-supporting databases—all feasible with GlueSQL. It can also operate with storages supported in web browsers.

GlueSQL's essential feature is providing a management layer for these diverse storage scenarios without requiring data migration. The broader aim is to facilitate portability of GlueSQL to any environment supporting read or read-write operations. This extends to APIs like GitHub, or messengers like Discord or Slack.

GlueSQL supports both structured and unstructured data and is written in Rust for compatibility with various environments. While portability is its core value, the emphasis is on creating an intuitive, comfortable development environment for easy custom storage implementation.

Ultimately, GlueSQL aims to significantly reduce the cost, time, and complexity of developing new databases. By leveraging GlueSQL for the parser, planner, and execution layer, developers can focus on creating specific storage implementations, leading to a more convenient query interface like SQL for many environments.

The Problem: Why Reinvent the Database?

Despite the numerous database implementations that currently exist, the emergence of new databases continues. The primary reason behind this trend is our need for databases for a broad spectrum of distinct purposes. For instance, new databases are surfacing that are specifically optimized for Large Language Models (LLMs) like ChatGPT. The range is wide and diverse, encompassing embedded databases, OLAP for data analysis, OLTP databases optimized for online transactions, databases specialized for time-series data processing, and many more.

With such varied requirements, we find ourselves in constant need of fresh databases. However, constructing a database from scratch is a monumental task. It necessitates defining a query interface for handling the database and implementing a corresponding parser. Moreover, a separate execution layer for running operations must be built. Also, the planning layer, which is responsible for devising execution strategies, is a vital aspect of this process. Let's not forget about the critical storage layer that physically reads and stores the data. In a nutshell, there's a daunting amount of work involved in developing a new database.

Given these circumstances, it's understandable why numerous emerging databases resort to high pricing structures—they need immediate revenue to offset continuous development costs.

But the story doesn't end here. Query interfaces like SQL are indeed useful for serious tasks, but they also provide excellent utility for handling simple log files such as CSV, JSONL, Parquet, and even for utilizing REST APIs for various applications. The issue arises when a complex query interface needs to be provided even for these lighter storage requirements—it necessitates a development process almost identical to building a sophisticated database. Implementing an entire parser and execution layer just to add SQL support to an existing service can seem like an excessive burden.

Whether it's a simple storage environment or a serious task, the key lies in the storage layer, which involves the actual reading and storing of data. So, what if developers focused on implementing these storage mechanisms while the remaining parts could be handled using existing libraries? This is the role that GlueSQL aspires to play.

The Vision of GlueSQL

The GlueSQL project aims to offer a unified query interface for various environments. The goal is to allow anyone to port and use SQL and GlueSQL's proprietary query builder, the AST Builder, in any desired environment. This could range from key-value databases, serious NoSQL databases, log files, and even REST API services. Essentially, if a service supports reading or read-writing data, regardless of the data type, it can readily support a complex query interface via GlueSQL.

Presently, the GlueSQL project itself directly supports a few storage types as reference storages. These include in-memory storage for non-persistent data handling, sled storage, which is a key-value database written in Rust, JSON storage for handling JSON and JSONL files, and a storage that ports SQL to the web browser's IndexedDB. While the GlueSQL Team is primarily developing these, the aim is to allow anyone to create such custom storages for a wide array of purposes, thus enabling them to assemble the database of their choosing.

Imagine using GlueSQL's SQL and AST Builder everywhere, with the simple method of swapping out storages to operate in diverse settings. It could significantly reduce software development costs. Developers wouldn't need to learn the different usage methods for each database. Instead, they could focus solely on implementing business logic using the same interface.

Our vision is to reduce database development costs by 10 times, or even more than 20 times. We aim to gather diverse database creators under the GlueSQL banner, making it the go-to solution for cost-effective database development.

Benefits to Database Users: Unifying Query Interfaces, Streamlining Software Development, and Reducing Costs

From the perspective of the users who engage with databases, there has always been the burden of learning different interfaces to interact with each database. The approach required to work with Redis is different from that necessary for MongoDB. Likewise, handling SQL databases necessitates using SQL. Although SQL databases generally use a common SQL, the SQL they support can considerably vary when examined in detail.

Naturally, there are legitimate reasons for such differences. Each database focuses on different areas, and to cater to specialized functionalities, they incorporate dedicated interface mechanisms. However, not all application development needs to utilize these database-specific core special functionalities.

Let's look at a couple of examples:

Suppose you're developing a back-end application that uses MySQL as the database and Redis for caching. Due to the vast differences in handling SQL databases and Redis, you would have to develop using different methods when storing data.

Here's another scenario: +Imagine you're implementing a data migration pipeline between various databases and log files. Let's say you're transferring Parquet to Redis or MongoDB. In this case, you would need to convert data using different methods for each, all of which would be a cumbersome process.

In both of the above examples, GlueSQL can directly address and solve the issues. It offers the convenience of a uniform query interface to deal with these matters. In certain scenarios, even the construction of a data pipeline can potentially be solved with a single SQL query, thanks to GlueSQL.

Benefits to Database Developers: Drastically Lowering Development Costs and Simplifying the Creation of Purpose-Built Databases

If you want to support SQL in the desired environment, using GlueSQL essentially requires you to implement an interface for Storage. There's no need to support all functionalities from the beginning. You can start lightly, choosing and implementing storage features suitable for the environment you want to create. To facilitate this, GlueSQL also provides a library in the form of a test suite to easily validate the storage you've implemented.

Lowering development costs in this way will enable a broader range of developers to support the GlueSQL query interface. As more developers join, a significant synergy can be generated. Designing a query interface from scratch involves a great deal of work, including planning and supporting the interface for different target programming languages.

However, despite all this hard work, it is not easy to attract database users accustomed to different methods.

Consider that the SQL and AST Builder provided by GlueSQL are already securing numerous users. This eliminates the need for efforts to promote a newly planned query interface. Over the years, many new databases have emphasized compatibility with PostgreSQL or MySQL for similar reasons. As GlueSQL places a strong emphasis on portability in its query interface planning, it allows for more flexible configuration according to the desired situation. Through the AST Builder, it also eliminates the cost of porting to different languages.

For many database developers, using GlueSQL can be an optimal choice, as it can save costs and quickly secure users.

Let me mention one more thing: what's convenient for humans... could be applied to AI as well. Rather than making AI write automation code using different databases, providing a common query interface can be much more efficient.

The Future with GlueSQL

GlueSQL has been and will continue to improve and develop new features to enable portability in various environments. Thanks to the schemaless data support added last year, it is now possible to handle both structured data with schema and unstructured data like JSON simultaneously. This has significantly increased the range of storage environments that can be supported.

One of the key features added last year was the AST Builder. This feature allowed us to escape the confines of SQL and provide an interface for comfortably handling data in the programming languages used for development.

Of course, improving existing features is extremely important, and there are many new features to be added. As a major development plan this year, we aim to develop features to effectively attach GlueSQL to NoSQL databases with their own planners and execution layers. The GlueSQL query planner, currently at a basic level, will see significant changes this year. With the expansion of this planner, not only NoSQL databases but also other SQL databases could be supported without sacrificing performance using GlueSQL.

The synergy that arises from the combination of different databases is a significant bonus in this process.

The Journey of the GlueSQL Team

The GlueSQL project was first conceived in the fall of 2019, and since then we have been developing it continuously. Personally, I have created various products in a variety of environments, including game development, backend server, and frontend development over the past decade. The experience gained through this process was a major motivation to start the GlueSQL project.

To put it grandly, the inconveniences felt while using different databases in various environments were a major motivation, wouldn't you say?

The start was actually a bit simple. Around 2019, I was mainly doing web front-end development. However, the lack of a structured database for state management and internal data processing made it very uncomfortable, especially since I couldn't use SQL databases and the like. So I started to lightly create an SQL database that could run on a web browser. Also, I wanted to use Rust, but after failing to introduce it at the company I was working for at the time, I decided to use it in my own project.

But as I started developing, my dreams grew significantly. Beyond a SQL database that simply operates on a web browser, I started envisioning a database that fits the name "Glue", one that can easily be ported to various environments, and I continue that journey to this day.

Whether I took the database project too lightly, or because the features I wanted kept increasing, the content to be developed kept expanding. As a result, I ended up investing full time in the GlueSQL project development for over three years. For a year in between, I even juggled full-time software engineering work alongside GlueSQL development. Currently, I'm back to developing the GlueSQL project full time, alongside various part-time contributors.

Now, we're getting very close to the starting point of the picture I wanted to create through GlueSQL, and thankfully, with contributors joining me, I am not alone.

The Sustainability and Business Aspect of GlueSQL

I believe that what we create through GlueSQL will make a great contribution to the world and make many software engineers happy. This gives me immense strength to continue developing even in difficult situations. However, we cannot accomplish everything with pure passion alone. As much as the GlueSQL project can make a significant contribution, I also see it as holding great business value.

The business strategy of GlueSQL may be somewhat different from other databases. We distribute the project itself as open source under the Apache-2.0 license, so that anyone can use it fully, and we do not consider pricing methods such as restricting features to the storages we support. In fact, if there is any player who can do it better, there's no way to prevent them from taking the GlueSQL project and making it their own.

But we believe that GlueSQL has great potential in this regard. Anyone can participate and they are free to distribute their own storage in the way they want, whether it's open source, private, or commercial. This eliminates the need to create something to replace the GlueSQL project. We aim to prevent the need to recreate the wheel that we provide using GlueSQL.

Moreover, our GlueSQL team seeks to continually expand our group of developers and companies working with us. During this development process, while they can certainly implement everything on their own, there is also no reason not to collaborate with our GlueSQL Team, especially for databases like NoSQL that have their own planners and execution layers. If you have a REST API and want to enhance convenience through SQL support, you can do it yourself or you can collaborate with us.

In addition, for some storages, we can also participate as players in the same position as other custom storage developers. We plan to expand the GlueSQL ecosystem in various ways, such as technical support and storage development.

We are finally ready to provide GlueSQL to users at the production level. We are accelerating the development of GlueSQL. If you are a company interested in storage development like SQL support, or if you resonate with our vision and want to join us, please contact us at taehoon@gluesql.com.

Conclusion

The continued emergence of new databases is driven by the demand for diverse and specialized databases, such as those optimized for Large Language Models (LLMs) and databases catering to unique requirements, like embedded databases, OLAP, OLTP, and time-series data processing. However, developing a new database from scratch is a significant undertaking, requiring extensive work, which often results in high costs.

GlueSQL presents a solution to this challenge by providing a unified query interface that can be ported across various environments, from key-value databases, NoSQL databases, log files, to REST APIs. It allows anyone to create custom storages, reducing the need for developers to build entirely new databases and to learn different usage methods for each database. Instead, they can focus on implementing their business logic using the same interface.

From a user perspective, GlueSQL offers the convenience of a unified query interface, easing the burden of learning different interfaces for each database. This simplification of interface use can also extend to AI, potentially enhancing the efficiency of AI automation.

GlueSQL's development plan includes significant enhancements to its query planner and aims to enable effective attachment of GlueSQL to NoSQL databases. The synergy of combining different databases is a valuable bonus in this process.

Since its inception in the fall of 2019, the GlueSQL team has continuously developed the project, driven by the desire to mitigate the inconveniences encountered while using different databases in various environments. The journey has been a rewarding one, with the GlueSQL project now at a point where it closely resembles the envisioned product.

GlueSQL, distributed under the Apache-2.0 license, is free for anyone to use and adapt. While the GlueSQL team welcomes collaboration with other developers and companies, they also see significant potential for the project as a business venture. The team is working to expand the GlueSQL ecosystem through a variety of initiatives, including technical support and storage development.

With GlueSQL now sufficiently prepared for practical applications, the team invites companies interested in storage development or those who share their vision to join them in their journey of revolutionizing database development.

]]>
+ gluesql + query-interface + database + proposal +
+ + <![CDATA[Test-Driven Documentation - Automating User Manual Creation in GlueSQL]]> + https://gluesql.org/docs/0.16.0/blog/test-driven-documentation + https://gluesql.org/docs/0.16.0/blog/test-driven-documentation + Tue, 30 May 2023 00:00:00 GMT + + Introduction: GlueSQL and Test-Driven Documentation

Recently, the GlueSQL project reached a significant milestone with the release of version 0.14. This new version brings a host of fresh features to the table, yet one of the most notable changes is in the realm of documentation. For the first time, we're proud to announce the launch of our official documentation website. Interested readers can explore the full range of user manuals at https://gluesql.org/docs.

Prior to this update, the only way to navigate GlueSQL was by manually inspecting the test code within the test suite. With the recent release, however, a comprehensive user manual has been made public to facilitate a more user-friendly experience. We hope that this new addition will prove beneficial to a broad spectrum of users.

The task of compiling an entire database manual in one go was daunting due to the sheer volume of content required. Surprisingly, this process turned out to be smoother than initially anticipated, largely due to the invaluable aid of ChatGPT, which was instrumental in automating much of the document creation. Specifically, around 80% of the SQL Syntax section was generated using this tool.

This remarkable feat was only possible due to the solid foundation of test codes previously established in GlueSQL. In this article, we'll share how we managed to leverage ChatGPT in such a unique way. Based on our recent experience of crafting documents grounded in testing, we've begun to consider the possibility of entirely automating document creation, save for the initial stages.

Along with sharing our journey so far, we will also reveal our plans for future test-based automation of documentation within GlueSQL.

Test Codes and Documentation

The GlueSQL project has placed a significant emphasis on writing test codes. This might be a given for a database project; however, the thoroughness of our approach is evident from our line coverage of nearly 99% for core codes. While we devoted considerable effort to creating these test codes, our primary focus has always been on a different aspect: ensuring that anyone can quickly grasp the content of the tests and easily add new ones.

The intent here is to empower newcomers to GlueSQL to understand the functionality of the software solely by examining integration tests, even in the absence of a user manual.

The integration tests for GlueSQL can be found in the test-suite workspace. For example, here's an excerpt of the test code for the INSERT statement:

test_case!(insert, async move {
run!(
"
CREATE TABLE Test (
id INTEGER DEFAULT 1,
num INTEGER NULL,
name TEXT NOT NULL,
);"
);

test! {
name: "basic insert - single item",
sql: "INSERT INTO Test (id, num, name) VALUES (1, 2, 'Hi boo');",
expected: Ok(Payload::Insert(1))
};


test! {
sql: "INSERT INTO Test VALUES(17, 30, 'Sullivan');",
expected: Ok(Payload::Insert(1))
};

test! {
sql: "INSERT INTO Test (num, name) VALUES (28, 'Wazowski');",
expected: Ok(Payload::Insert(1))
};

test! {
sql: "SELECT * FROM Test;",
expected: Ok(select!(
id | num | name;
I64 | I64 | Str;
1 2 "Hi boo".to_owned();
3 9 "Kitty!".to_owned();
2 7 "Monsters".to_owned();
17 30 "Sullivan".to_owned();
1 28 "Wazowski".to_owned()
))
};

// ...
});

Despite being written in Rust, these test cases are designed to be comprehensible, even to those unfamiliar with the language. Each test is a complete scenario from start to finish, and the results of each operation are readily observable.

Given that identifying results from SELECT operations in the form of Rust enums and structs can be challenging, we actively utilized macros such as select! and select_with_null!. We've composed the test cases to demonstrate that the INSERT statement can handle a wide range of cases, including specifying all columns, omitting some, or omitting all.

test! {
sql: "INSERT INTO Test (id, num) VALUES (1, 10);",
expected: Err(InsertError::LackOfRequiredColumn("name".to_owned()).into())
};

The tests also include scenarios for expected faulty inputs, indicating the error returns in these situations.

By organizing the tests in this manner, we aim to make it easy for anyone to read and write tests. Our goal was for these tests to serve as "documentation" for GlueSQL contributors. At the time we were writing these tests, we didn't anticipate that they could actually become documentation themselves. But we've come to realize that they have extraordinary potential.

Leveraging ChatGPT

When we first embarked on writing the User Manual, we were overwhelmed by the sheer volume of content we had to generate. Around the same time, ChatGPT was gaining prominence, and we thought it might be worth trying out, if only to lighten our load slightly.

To our surprise, ChatGPT exceeded our expectations. If the test codes were well written, it was capable of automatically crafting an exceptional document based on them, capturing all essential details.

After several trials and errors, we settled on the following prompt for document generation. While it's still a challenge to use the same prompt for all documentation, we made minor modifications to suit different situations:

I'm creating an SQL database documentation website, and I'd like you to help me with one of the pages that introduces the SQL syntax for GlueSQL.

1. Please provide the response content in the "markdown" format, so I can copy and paste it directly. Keep this constraint in mind while writing.
2. Regardless of the language I use, I need the content written in English.
3. I will provide some test case code written in the Rust language, which contains SQL examples. Please write the documentation based on these examples, but feel free to change the table names, column names, and data types as needed. Don't include any Rust related content or text in the response. all the response code example should be in plain SQL.
4. GlueSQL does not have the VARCHAR type. If you want to use that, please use TEXT instead. You don't need to mention this in the response.
5. Wrap the entire response text using <pre> and </pre> tags so I can copy all the content easily.

Now, I'd like you to write the following request:
SQL Statement - "INSERT"

Here's an example test code you can refer to:

test_case!(insert, async move {
run!(...

Generally, we used the template above, and copied and pasted the test code from our existing test-suite. We leveraged this method to harness our many tests to assist in the creation of the user manual. In the next section, we'll showcase a sample of the documentation generated in this manner. It's quite impressive.

Success Case: Automated User Manual of GlueSQL

Thanks to ChatGPT, the resulting INSERT document page can be viewed at the following link. It's important to note that we used ChatGPT 4 for this task. Version 3.5 wasn't quite up to the task, and using version 4 was the minimum requirement.

https://gluesql.org/docs/dev/sql-syntax/statements/data-manipulation/insert

INSERT Statement

The results were quite impressive. ChatGPT neatly categorized the test cases, explained the syntax, outlined constraints, and provided appropriate examples. It didn't stop there; it also skillfully recognized error test cases and incorporated them into the documentation, as shown below.

INSERT Statement

Isn't it amazing?

Future Plans: Fully Automating Documentation Generation

While the current documentation is far from perfect and there are many aspects that can be improved, we see great potential in this approach. We believe it's entirely possible to automate the process of writing this kind of document, and writing in general.

In the past, documents like user manuals required a great deal of effort to maintain once they were written. If a document contained real code examples, verifying that the code still worked was often a tedious task. With the ability to automatically generate documentation as we have done here, these issues are no longer problematic.

Previously, you would have to write tests and then also document them separately. If you had to support multiple languages, that would be an additional task. With a tool like ChatGPT, you can automate all of this. All a developer has to do is write the tests. This alone can be sufficient. You can generate documents automatically based on the tests. Eventually, we can even support automatically translating these documents into multiple languages.

The GlueSQL project repository is currently hosted on GitHub and makes good use of various GitHub Actions. We envision a GitHub Action that automatically regenerates a document corresponding to a test when a user modifies the test and raises a Pull Request. Another GitHub Action could automatically translate updated documents into supported languages and create new Pull Requests. The possibilities are truly endless.

Not only will this help with document generation, but it will also provide clear guidelines for writing better test code. If we can automatically generate documents based on written tests, the quality of those documents can serve as an indicator of the quality of the tests themselves. This means that a document automation tool can play the role of a good reviewer for tests. It can greatly reduce the time and effort required for painstakingly reviewing the quality of each test. Developers can also write tests without pressure, evaluate their test code by looking at the generated document, and improve it.

Furthermore, multi-language support becomes a breeze. In my personal experience as a software engineer over the past decade, developing various products such as games, web services, and applications, I often needed to support multiple languages. Each time, there was no definite solution. The optimal approach varied depending on the situation, and there were many things to consider when entrusting translations, such as effectively communicating the context of the target service to the translator. Moreover, regularly updating content and having it retranslated into various languages was a very tedious process. While I tried to automate as much as possible by creating various tools, I was never fully satisfied. I believe ChatGPT can completely solve these issues. If there is a need to provide project-specific context, all you need to do is prepare a prompt in advance. Instead of having to rely on and wait for professional translators, we can now entrust this task to ChatGPT, and we only need a few people to review the translated content.

We are nearing a world where documentation is no longer a burden for developers.

Conclusion: The Value of Test-Driven Documentation

The use of ChatGPT to generate documentation has proven a significant step forward in the GlueSQL user manual creation process. Through test-driven documentation, we've managed to automate a substantial part of the manual creation process, saving time and effort, and increasing accuracy.

Moreover, this process has unveiled a new potential for documentation: the possibility of fully automating document generation. We've seen that quality tests can become quality documentation with the help of AI, leading to more efficient workflows and possibly better test code as a result.

The journey doesn't stop here. We envision leveraging this capability further to auto-translate our documents into multiple languages, making our product more accessible to a global audience.

As we progress, we hope that our experience can inspire other developers to explore and embrace the benefits of AI-generated, test-driven documentation. It's not just about saving time—it's about improving the way we work, communicate, and share knowledge.

]]>
+ ChatGPT + Test-Driven-Documentation + TDD + Database + Documentation + Automation +
+ + <![CDATA[Breaking the Boundary between SQL and NoSQL Databases]]> + https://gluesql.org/docs/0.16.0/blog/breaking-the-boundary-between-sql-and-nosql + https://gluesql.org/docs/0.16.0/blog/breaking-the-boundary-between-sql-and-nosql + Mon, 29 May 2023 00:00:00 GMT + + Introduction

The divide between SQL and NoSQL databases has often presented challenges in database management. GlueSQL, a unique database maker library, aims to blur this boundary, providing a versatile tool for handling these two distinct types of databases.

In this article, we explore how GlueSQL navigates the features of SQL and NoSQL databases, offering an integrated solution that promotes flexibility and efficiency. With its ability to unify disparate database types, GlueSQL heralds a new age of adaptable database creation and management.

The Interface Perspective: SQL & AST Builder

When we talk about SQL databases, it's almost a given that they support SQL - the standard query language. Although there are slight variations between databases, the convenience of using a similar SQL language across multiple databases cannot be overstated. However, from a software engineer's perspective, there's room for improvement. In most software development scenarios, a specific programming language is used. SQL is a separate language, which can cause friction when integrating it into your software. As a result, rather than using raw SQL, many developers employ query builders or ORMs to manipulate SQL conveniently using their preferred programming language. Although it's not efficient to generate SQL using a query builder and then parse it again in the database, it's a practical and effective choice.

On the other hand, NoSQL databases offer different mechanisms. Some of them have their own language similar to SQL, but most provide an interface library developed specifically for each programming language. While SQL databases rely on external query builder libraries to provide an interface for each programming language, NoSQL databases mostly develop and offer these libraries themselves. If we discount the convenience of SQL language, this is one of the major factors that make NoSQL databases more comfortable to use. Since query builder libraries supporting SQL databases often cater to multiple SQL databases, they are limited in fully supporting unique features of each database. NoSQL databases, on the other hand, can freely manage their interface libraries without these restrictions.

Providing a query interface for each programming language is not a fundamental difference between SQL and NoSQL, but we generally accept it implicitly.

Let's see what happens if we break down this boundary, using GlueSQL as an example. As you can see from the SQL postfix, GlueSQL supports SQL and can be classified as an SQL database.

CREATE TABLE Glue (id INTEGER, name TEXT);

INSERT INTO Glue VALUES (1, "hello"), (2, "gluesql");

SELECT * FROM Glue WHERE id = 1;

However, GlueSQL also supports its own query builder, like a NoSQL database. +(Currently, only Rust is supported, but we're working on adding support for other languages.)

table("Glue")
.create_table()
.add_column("id INTEGER")
.add_column("name TEXT")
.execute(glue)

table("Glue")
.insert()
.values(vec![
vec![num(1), text("hello")],
vec![num(2), text("gluesql")],
])
.execute(glue)
.await;

table("Glue")
.select()
.filter(col("id").eq(1))
.execute(glue)
.await;

Let's reconsider the implicit distinction between SQL and NoSQL. GlueSQL indeed supports SQL, but it also officially develops and offers its own query builder. This query builder is not a secondary tool for SQL. While most SQL query builder libraries ultimately generate SQL strings, GlueSQL's builder directly creates an AST (Abstract Structure Tree) that is used for execution within GlueSQL. Hence, we call it the AST Builder. This means SQL and the AST Builder are two equally supported interfaces in GlueSQL.

This also offers an additional advantage:

table("Glue")
.select()
// 1.
.filter(col("id").eq(1))
// 2.
.filter("id = 1")
.execute(glue)
.await;

Because GlueSQL already supports SQL, not only can you use the custom interface in the AST Builder, but you can also use familiar SQL syntax in part. Whether you use col("id").eq(1) or "id = 1", you can use it in the way you prefer. The AST Builder interface, although initially unfamiliar, allows a gradual migration similar to writing SQL for your convenience.

Thus, we've dismantled one of the implicit distinctions between SQL and NoSQL. However, it's more of an implicit differentiation than a fundamental one. There are more significant design differences that we'll explore next.

Structured & Unstructured Data

In this section, we'll discuss how SQL and NoSQL handle data. SQL generally deals with structured data, and recently, it's been made to support semi-structured data as well. On the other hand, NoSQL supports schemaless, unstructured data. Then, we'll explain in detail how GlueSQL handles these two types of data. The last part of this section will provide a segue into the next section where we'll discuss the decomposition of database functions.

When talking about SQL databases, one aspect is usually considered together: SQL databases have a defined schema.

CREATE TABLE Foo (
id INTEGER,
name TEXT,
rate FLOAT NULL
);

However, these days, SQL databases tend to support semi-structured data types, such as LIST or JSON. But, supporting completely schemaless, unstructured data is a different matter. SQL databases typically require a minimum schema.

What about NoSQL databases? As NoSQL databases vary significantly, we can't make definitive statements. But let's consider a typical document database like MongoDB. Unlike SQL databases, it doesn't enforce a schema. Essentially, you can insert any form of data directly. Often, NoSQL databases support schemaless data, but they lack features that enforce a schema like SQL. They generally support structure via validation methods, rather than structured access.

Is there no choice but to distinguish between structured data and unstructured, schemaless data so clearly? GlueSQL is being developed with the goal of being adaptable in various environments. Being forced to choose regarding this schema constraint was quite inconvenient. We started pondering if we couldn't benefit from both aspects - supporting both schema and schemaless data simultaneously, and we eventually found the answer. Let's look at how GlueSQL currently solves this issue through familiar SQL examples.

CREATE TABLE Names (id INTEGER, name TEXT);
INSERT INTO Names VALUES (1, 'glue'), (2, 'sql');

You can create a regular table with a schema like this. But GlueSQL's choice for creating a schemaless table is as follows:

CREATE TABLE Logs;
INSERT INTO Logs VALUES
('{ "id": 1, "value": 30 }'),
('{ "id": 2, "rate": 3.0, "list": [1, 2, 3] }'),
('{ "id": 3, "rate": 5.0, "value": 100 }');

It creates a table without column definitions! If you do this, GlueSQL recognizes the table as schemaless and processes it internally.

SELECT id, rate, list[0] FROM Logs WHERE id = 2;

Although the way to create the table was a bit special, using it isn't much different from the regular SQL SELECT statement. Not only can you differentiate between schema and schemaless when creating tables, but you can also use them interchangeably!

SELECT * FROM Names JOIN Logs ON Names.id = Logs.id;
/*
| id | list | name | rate | value |
|----|---------|------|------|-------|
| 1 | | glue | | 30 |
| 2 |[1, 2, 3]| sql | 3 | |
*/

Here's an example of querying data by INNER JOINing the Names table, which has a schema, and the Logs table, which is schemaless. GlueSQL has resolved this problem by allowing the internal execution layer to handle both vector-type data, for cases where each row has a defined schema, and map-type data for schemaless cases.

Thanks to this, the variety of storage that can be supported through GlueSQL has expanded significantly. If there were previously limitations to supporting NoSQL databases that support schemaless data, that is no longer the case. The reference storage where you can directly experience this schemaless data support is JSON Storage. It offers features that allow you to deal directly with unstructured data like JSON using GlueSQL.

If GlueSQL starts from the perspective of an SQL database and expands, by providing the AST Builder directly, it once blurs the boundary, and by supporting unstructured data simultaneously, it knocks down the boundary once more. How do you like it?

Decomposing Database Functionality: Breaking Down SQL and NoSQL Features

The distinction between SQL and NoSQL is not just about whether they support unstructured data. Of course, there are examples like unstructured data, which is mainly supported only in NoSQL, but in many cases, SQL databases tend to support more diverse and complex queries. NoSQL often gains other advantages in exchange for reducing the range of query support provided by SQL databases.

GlueSQL is ambitious. It has devised a rather interesting method to support all of this through SQL and the AST Builder, with the same interface. When we usually say SQL database, it implicitly assumes that a lot of features have been fully implemented. Create tables by specifying a schema, modify schemas with "alter table", support both clustered and non-clustered indexes, and support transactions. And there's so much more. But the functionality that is naturally supported in SQL databases may not be natural in other environments.

Let's think about JSON Storage. GlueSQL's JSON Storage allows you to handle JSON, JSONL files using SQL and the AST Builder. This JSON Storage does not support atomic operations or transactions. Of course, it would be great if it did, but implementing and executing them would be a significant performance burden. In most cases, when you want to simply browse and handle JSONL files, the overhead caused by transactions can be an unnecessary burden. In this case, you want to handle JSON, JSONL files using SQL, but you don't necessarily need transactions.

To meet the requirements of these diverse environments, GlueSQL has separated the functionality of what we usually call an SQL database into multiple independent interfaces. +Store, StoreMut, AlterTable, Transaction, .. +These are just a few of the various storage interfaces that GlueSQL currently supports. +The way it works can be summarized like this: +If you implement Store, you can use SELECT. +And if you implement both Store and StoreMut, you can support quite a number of basic SQL statements including SELECT. +You can manage tables with CREATE TABLE, DROP TABLE, and handle data using INSERT, UPDATE, DELETE statements. +If you only need to retrieve data, you only need to implement Store. +If you want to support the ALTER TABLE statement, you can additionally implement the AlterTable interface. +The Transaction interface works the same way. +The interesting part is that, except for Store and StoreMut, all other storage interfaces can be implemented independently. GlueSQL allows you to choose and implement only the features you need. +And it's not just about providing interfaces. It also provides integration tests suitable for each situation to verify what you have implemented. You just need to implement the interface and import the corresponding test case for verification.

In addition to supporting both structured and unstructured data simultaneously, GlueSQL provides the ability to divide the functionality of a database into multiple independent features and selectively implement them. This allows GlueSQL to be ported to a wide variety of environments without any burden.

Conclusion

GlueSQL, while serving as a database that provides its own reference storage, is fundamentally a library designed to simplify the creation of databases. One of the substantial challenges GlueSQL had to overcome in order to support a diverse array of environments was to address the distinctive features that separate conventional SQL databases from NoSQL databases. GlueSQL achieved this through several innovative approaches, managing to support both categories simultaneously despite their significantly different characteristics.

It offers support for SQL alongside an AST Builder, and accommodates both structured and unstructured data. Additionally, it decomposes database functionalities into multiple independent features, allowing each environment to selectively implement the functionalities it requires.

These unique attributes enable GlueSQL to live up to its 'Glue' prefix by facilitating effortless porting across various environments. While we have been developing it for several years, there is still much ground to cover. However, the fact that we are now able to introduce it publicly attests to our successful technological validation and completion of a demonstrable level of implementation.

Through GlueSQL, we hope to provide developers with a unified query interface that can be customized according to their needs, thereby enabling them to produce efficient products more effortlessly. There's a promising future ahead for GlueSQL, and we look forward to its contributions to the technology community.

]]>
+ sql + database + nosql +
+ + <![CDATA[Release v0.14]]> + https://gluesql.org/docs/0.16.0/blog/release-v0.14 + https://gluesql.org/docs/0.16.0/blog/release-v0.14 + Sat, 27 May 2023 00:00:00 GMT + + We now provide an official documentation website at https://gluesql.org/docs

🚀 Features

🍀 Schemaless data support

GlueSQL now supports creating tables without a schema, allowing for both structured and unstructured data to be stored in the same table. +To create a schemaless table, simply run CREATE TABLE without specifying any columns. For more information on querying schemaless data, please refer to the following link: querying schemaless data

CREATE TABLE Bar;

To insert values,

INSERT INTO Bar VALUES
('{ "name": "ast", "value": 30 }'),
('{ "name": "glue", "rate": 3.0, "list": [1, 2, 3] }'),

Then, selecting values from schemaless table is simple.

SELECT name, rate, list[0] FROM Bar WHERE name = 'glue';

e.g.

CREATE TABLE Names (id INTEGER, name TEXT);
INSERT INTO Names VALUES (1, 'glue'), (2, 'sql');

CREATE TABLE Logs;
INSERT INTO Logs VALUES
('{ "id": 1, "value": 30 }'),
('{ "id": 2, "rate": 3.0, "list": [1, 2, 3] }'),
('{ "id": 3, "rate": 5.0, "value": 100 }');

SELECT * FROM Names JOIN Logs ON Names.id = Logs.id;
/*
| id | list | name | rate | value |
|----|---------|------|------|-------|
| 1 | | glue | | 30 |
| 2 |[1, 2, 3]| sql | 3 | |
*/

🍀 IndexedDB & WebStorage supports in JavaScript package

GlueSQL supports handling in-memory, localStorage, sessionStorage, and even IndexedDB using the same SQL syntax. All you need to know is how to specify the ENGINE when creating a table.

e.g.

CREATE TABLE Mem (mid INTEGER) ENGINE = memory;
CREATE TABLE Loc (lid INTEGER) ENGINE = localStorage;
CREATE TABLE Ses (sid INTEGER) ENGINE = sessionStorage;
CREATE TABLE Idb (iid INTEGER) ENGINE = indexedDB;

SELECT
mid, lid, sid, iid
FROM Mem
JOIN Loc
JOIN Ses
JOIN Idb;

🍀 Data Types - UINT32, UINT64, UINT128, POINT and FLOAT32

🍀 Functions - APPEND, PREPEND, RAND, FIND_IDX, INITCAP and CALC_DISTANCE

🍀 Store traits

User-level custom function

By implementing both the CustomFunction and CustomFunctionMut traits, users can create, use, and delete user-level custom functions. Although GlueSQL plans to continuously add various functions, users may still find them insufficient. In such cases, users can create their own user-level custom functions to supplement the built-in functions. Additionally, if there are repetitive business logic codes, they can be stored as custom functions. +e.g.

CREATE FUNCTION ADD_ONE (n INT, x INT DEFAULT 1) RETURN n + x;

SELECT ADD_ONE(10) AS test;

DROP FUNCTION ADD_ONE;

Metadata

The Metadata trait is an optional implementation for providing additional metadata support in GlueSQL. GlueSQL does not enforce any specific metadata implementation, allowing custom storage developers to decide which type of metadata, such as create time, modify time, etc., they want to provide.

🍀 Storages

JSON Storage

Composite Storage

  • Add CompositeStorage which bundles multiple storages @panarch (#1068)

IndexedDB Storage

Web Storage

  • Add WebStorage - support localStorage \& sessionStorage for web browsers @panarch (#1050)

🍀 Other new features

🌊 Interface Changes

  • Remove Store trait related cfg features, @panarch (#1091)
  • Refactor CreateTable.columns from Vec<ColumnDef> to Option<Vec<ColumnDef>> @devgony (#1086)
  • Remove MutResult @panarch (#1073)
  • Update all store mut trait methods to take \&mut self @panarch (#1072)
  • Change StoreMut interface to use \&mut self, not to take ownership @panarch (#1071)
  • Modify default ColumnOption from NOT NULL to NULL @devgony (#997)

🌟 Improvements

🌳 Documentation

We now provide an official documentation website at https://gluesql.org/docs

Docs - setup

📋 Tests

🐛 Bug Fixes

  • Fix docusaurus pages/index broken link @panarch (#1214)
  • Fix docs/ Discord GlueSQL channel invite link address @panarch (#1213)
  • Fix InvalidJsonString error message replacing payload to fileName @devgony (#1185)
  • Fix TryFrom Value::Str to u128 not to use parse_uuid @ChobobDev (#1134)
  • Fix column alias with identifer for TableFactor::Derived @ding-young (#1119)
  • Pass data even when deleted_by is not present @ever0de (#1117)
  • Fix MemoryStorage \& WebStorage primary key support @panarch (#1115)
  • Fix plan::validate to handle CTAS and ITAS adding unit test @devgony (#1074)
  • Fix test-suite tester functions to show (found, expected) shape @panarch (#1028)
]]>
+ v0.14 + release-note +
+
+
\ No newline at end of file diff --git a/docs/0.16.0/blog/tags/automation/index.html b/docs/0.16.0/blog/tags/automation/index.html new file mode 100644 index 00000000..5a3b6530 --- /dev/null +++ b/docs/0.16.0/blog/tags/automation/index.html @@ -0,0 +1,17 @@ + + + + + +One post tagged with "Automation" | GlueSQL + + + + + +
+

One post tagged with "Automation"

View All Tags

· 10 min read
Taehoon Moon

Introduction: GlueSQL and Test-Driven Documentation

Recently, the GlueSQL project reached a significant milestone with the release of version 0.14. This new version brings a host of fresh features to the table, yet one of the most notable changes is in the realm of documentation. For the first time, we're proud to announce the launch of our official documentation website. Interested readers can explore the full range of user manuals at https://gluesql.org/docs.

Prior to this update, the only way to navigate GlueSQL was by manually inspecting the test code within the test suite. With the recent release, however, a comprehensive user manual has been made public to facilitate a more user-friendly experience. We hope that this new addition will prove beneficial to a broad spectrum of users.

The task of compiling an entire database manual in one go was daunting due to the sheer volume of content required. Surprisingly, this process turned out to be smoother than initially anticipated, largely due to the invaluable aid of ChatGPT, which was instrumental in automating much of the document creation. Specifically, around 80% of the SQL Syntax section was generated using this tool.

This remarkable feat was only possible due to the solid foundation of test codes previously established in GlueSQL. In this article, we'll share how we managed to leverage ChatGPT in such a unique way. Based on our recent experience of crafting documents grounded in testing, we've begun to consider the possibility of entirely automating document creation, save for the initial stages.

Along with sharing our journey so far, we will also reveal our plans for future test-based automation of documentation within GlueSQL.

Test Codes and Documentation

The GlueSQL project has placed a significant emphasis on writing test codes. This might be a given for a database project; however, the thoroughness of our approach is evident from our line coverage of nearly 99% for core codes. While we devoted considerable effort to creating these test codes, our primary focus has always been on a different aspect: ensuring that anyone can quickly grasp the content of the tests and easily add new ones.

The intent here is to empower newcomers to GlueSQL to understand the functionality of the software solely by examining integration tests, even in the absence of a user manual.

The integration tests for GlueSQL can be found in the test-suite workspace. For example, here's an excerpt of the test code for the INSERT statement:

test_case!(insert, async move {
run!(
"
CREATE TABLE Test (
id INTEGER DEFAULT 1,
num INTEGER NULL,
name TEXT NOT NULL,
);"
);

test! {
name: "basic insert - single item",
sql: "INSERT INTO Test (id, num, name) VALUES (1, 2, 'Hi boo');",
expected: Ok(Payload::Insert(1))
};


test! {
sql: "INSERT INTO Test VALUES(17, 30, 'Sullivan');",
expected: Ok(Payload::Insert(1))
};

test! {
sql: "INSERT INTO Test (num, name) VALUES (28, 'Wazowski');",
expected: Ok(Payload::Insert(1))
};

test! {
sql: "SELECT * FROM Test;",
expected: Ok(select!(
id | num | name;
I64 | I64 | Str;
1 2 "Hi boo".to_owned();
3 9 "Kitty!".to_owned();
2 7 "Monsters".to_owned();
17 30 "Sullivan".to_owned();
1 28 "Wazowski".to_owned()
))
};

// ...
});

Despite being written in Rust, these test cases are designed to be comprehensible, even to those unfamiliar with the language. Each test is a complete scenario from start to finish, and the results of each operation are readily observable.

Given that identifying results from SELECT operations in the form of Rust enums and structs can be challenging, we actively utilized macros such as select! and select_with_null!. We've composed the test cases to demonstrate that the INSERT statement can handle a wide range of cases, including specifying all columns, omitting some, or omitting all.

test! {
sql: "INSERT INTO Test (id, num) VALUES (1, 10);",
expected: Err(InsertError::LackOfRequiredColumn("name".to_owned()).into())
};

The tests also include scenarios for expected faulty inputs, indicating the error returns in these situations.

By organizing the tests in this manner, we aim to make it easy for anyone to read and write tests. Our goal was for these tests to serve as "documentation" for GlueSQL contributors. At the time we were writing these tests, we didn't anticipate that they could actually become documentation themselves. But we've come to realize that they have extraordinary potential.

Leveraging ChatGPT

When we first embarked on writing the User Manual, we were overwhelmed by the sheer volume of content we had to generate. Around the same time, ChatGPT was gaining prominence, and we thought it might be worth trying out, if only to lighten our load slightly.

To our surprise, ChatGPT exceeded our expectations. If the test codes were well written, it was capable of automatically crafting an exceptional document based on them, capturing all essential details.

After several trials and errors, we settled on the following prompt for document generation. While it's still a challenge to use the same prompt for all documentation, we made minor modifications to suit different situations:

I'm creating an SQL database documentation website, and I'd like you to help me with one of the pages that introduces the SQL syntax for GlueSQL.

1. Please provide the response content in the "markdown" format, so I can copy and paste it directly. Keep this constraint in mind while writing.
2. Regardless of the language I use, I need the content written in English.
3. I will provide some test case code written in the Rust language, which contains SQL examples. Please write the documentation based on these examples, but feel free to change the table names, column names, and data types as needed. Don't include any Rust related content or text in the response. all the response code example should be in plain SQL.
4. GlueSQL does not have the VARCHAR type. If you want to use that, please use TEXT instead. You don't need to mention this in the response.
5. Wrap the entire response text using <pre> and </pre> tags so I can copy all the content easily.

Now, I'd like you to write the following request:
SQL Statement - "INSERT"

Here's an example test code you can refer to:

test_case!(insert, async move {
run!(...

Generally, we used the template above, and copied and pasted the test code from our existing test-suite. We leveraged this method to harness our many tests to assist in the creation of the user manual. In the next section, we'll showcase a sample of the documentation generated in this manner. It's quite impressive.

Success Case: Automated User Manual of GlueSQL

Thanks to ChatGPT, the resulting INSERT document page can be viewed at the following link. It's important to note that we used ChatGPT 4 for this task. Version 3.5 wasn't quite up to the task, and using version 4 was the minimum requirement.

https://gluesql.org/docs/dev/sql-syntax/statements/data-manipulation/insert

INSERT Statement

The results were quite impressive. ChatGPT neatly categorized the test cases, explained the syntax, outlined constraints, and provided appropriate examples. It didn't stop there; it also skillfully recognized error test cases and incorporated them into the documentation, as shown below.

INSERT Statement

Isn't it amazing?

Future Plans: Fully Automating Documentation Generation

While the current documentation is far from perfect and there are many aspects that can be improved, we see great potential in this approach. We believe it's entirely possible to automate the process of writing this kind of document, and writing in general.

In the past, documents like user manuals required a great deal of effort to maintain once they were written. If a document contained real code examples, verifying that the code still worked was often a tedious task. With the ability to automatically generate documentation as we have done here, these issues are no longer problematic.

Previously, you would have to write tests and then also document them separately. If you had to support multiple languages, that would be an additional task. With a tool like ChatGPT, you can automate all of this. All a developer has to do is write the tests. This alone can be sufficient. You can generate documents automatically based on the tests. Eventually, we can even support automatically translating these documents into multiple languages.

The GlueSQL project repository is currently hosted on GitHub and makes good use of various GitHub Actions. We envision a GitHub Action that automatically regenerates a document corresponding to a test when a user modifies the test and raises a Pull Request. Another GitHub Action could automatically translate updated documents into supported languages and create new Pull Requests. The possibilities are truly endless.

Not only will this help with document generation, but it will also provide clear guidelines for writing better test code. If we can automatically generate documents based on written tests, the quality of those documents can serve as an indicator of the quality of the tests themselves. This means that a document automation tool can play the role of a good reviewer for tests. It can greatly reduce the time and effort required for painstakingly reviewing the quality of each test. Developers can also write tests without pressure, evaluate their test code by looking at the generated document, and improve it.

Furthermore, multi-language support becomes a breeze. In my personal experience as a software engineer over the past decade, developing various products such as games, web services, and applications, I often needed to support multiple languages. Each time, there was no definite solution. The optimal approach varied depending on the situation, and there were many things to consider when entrusting translations, such as effectively communicating the context of the target service to the translator. Moreover, regularly updating content and having it retranslated into various languages was a very tedious process. While I tried to automate as much as possible by creating various tools, I was never fully satisfied. I believe ChatGPT can completely solve these issues. If there is a need to provide project-specific context, all you need to do is prepare a prompt in advance. Instead of having to rely on and wait for professional translators, we can now entrust this task to ChatGPT, and we only need a few people to review the translated content.

We are nearing a world where documentation is no longer a burden for developers.

Conclusion: The Value of Test-Driven Documentation

The use of ChatGPT to generate documentation has proven a significant step forward in the GlueSQL user manual creation process. Through test-driven documentation, we've managed to automate a substantial part of the manual creation process, saving time and effort, and increasing accuracy.

Moreover, this process has unveiled a new potential for documentation: the possibility of fully automating document generation. We've seen that quality tests can become quality documentation with the help of AI, leading to more efficient workflows and possibly better test code as a result.

The journey doesn't stop here. We envision leveraging this capability further to auto-translate our documents into multiple languages, making our product more accessible to a global audience.

As we progress, we hope that our experience can inspire other developers to explore and embrace the benefits of AI-generated, test-driven documentation. It's not just about saving time—it's about improving the way we work, communicate, and share knowledge.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/blog/tags/chat-gpt/index.html b/docs/0.16.0/blog/tags/chat-gpt/index.html new file mode 100644 index 00000000..ec3a1e5c --- /dev/null +++ b/docs/0.16.0/blog/tags/chat-gpt/index.html @@ -0,0 +1,17 @@ + + + + + +One post tagged with "ChatGPT" | GlueSQL + + + + + +
+

One post tagged with "ChatGPT"

View All Tags

· 10 min read
Taehoon Moon

Introduction: GlueSQL and Test-Driven Documentation

Recently, the GlueSQL project reached a significant milestone with the release of version 0.14. This new version brings a host of fresh features to the table, yet one of the most notable changes is in the realm of documentation. For the first time, we're proud to announce the launch of our official documentation website. Interested readers can explore the full range of user manuals at https://gluesql.org/docs.

Prior to this update, the only way to navigate GlueSQL was by manually inspecting the test code within the test suite. With the recent release, however, a comprehensive user manual has been made public to facilitate a more user-friendly experience. We hope that this new addition will prove beneficial to a broad spectrum of users.

The task of compiling an entire database manual in one go was daunting due to the sheer volume of content required. Surprisingly, this process turned out to be smoother than initially anticipated, largely due to the invaluable aid of ChatGPT, which was instrumental in automating much of the document creation. Specifically, around 80% of the SQL Syntax section was generated using this tool.

This remarkable feat was only possible due to the solid foundation of test codes previously established in GlueSQL. In this article, we'll share how we managed to leverage ChatGPT in such a unique way. Based on our recent experience of crafting documents grounded in testing, we've begun to consider the possibility of entirely automating document creation, save for the initial stages.

Along with sharing our journey so far, we will also reveal our plans for future test-based automation of documentation within GlueSQL.

Test Codes and Documentation

The GlueSQL project has placed a significant emphasis on writing test codes. This might be a given for a database project; however, the thoroughness of our approach is evident from our line coverage of nearly 99% for core codes. While we devoted considerable effort to creating these test codes, our primary focus has always been on a different aspect: ensuring that anyone can quickly grasp the content of the tests and easily add new ones.

The intent here is to empower newcomers to GlueSQL to understand the functionality of the software solely by examining integration tests, even in the absence of a user manual.

The integration tests for GlueSQL can be found in the test-suite workspace. For example, here's an excerpt of the test code for the INSERT statement:

test_case!(insert, async move {
run!(
"
CREATE TABLE Test (
id INTEGER DEFAULT 1,
num INTEGER NULL,
name TEXT NOT NULL,
);"
);

test! {
name: "basic insert - single item",
sql: "INSERT INTO Test (id, num, name) VALUES (1, 2, 'Hi boo');",
expected: Ok(Payload::Insert(1))
};


test! {
sql: "INSERT INTO Test VALUES(17, 30, 'Sullivan');",
expected: Ok(Payload::Insert(1))
};

test! {
sql: "INSERT INTO Test (num, name) VALUES (28, 'Wazowski');",
expected: Ok(Payload::Insert(1))
};

test! {
sql: "SELECT * FROM Test;",
expected: Ok(select!(
id | num | name;
I64 | I64 | Str;
1 2 "Hi boo".to_owned();
3 9 "Kitty!".to_owned();
2 7 "Monsters".to_owned();
17 30 "Sullivan".to_owned();
1 28 "Wazowski".to_owned()
))
};

// ...
});

Despite being written in Rust, these test cases are designed to be comprehensible, even to those unfamiliar with the language. Each test is a complete scenario from start to finish, and the results of each operation are readily observable.

Given that identifying results from SELECT operations in the form of Rust enums and structs can be challenging, we actively utilized macros such as select! and select_with_null!. We've composed the test cases to demonstrate that the INSERT statement can handle a wide range of cases, including specifying all columns, omitting some, or omitting all.

test! {
sql: "INSERT INTO Test (id, num) VALUES (1, 10);",
expected: Err(InsertError::LackOfRequiredColumn("name".to_owned()).into())
};

The tests also include scenarios for expected faulty inputs, indicating the error returns in these situations.

By organizing the tests in this manner, we aim to make it easy for anyone to read and write tests. Our goal was for these tests to serve as "documentation" for GlueSQL contributors. At the time we were writing these tests, we didn't anticipate that they could actually become documentation themselves. But we've come to realize that they have extraordinary potential.

Leveraging ChatGPT

When we first embarked on writing the User Manual, we were overwhelmed by the sheer volume of content we had to generate. Around the same time, ChatGPT was gaining prominence, and we thought it might be worth trying out, if only to lighten our load slightly.

To our surprise, ChatGPT exceeded our expectations. If the test codes were well written, it was capable of automatically crafting an exceptional document based on them, capturing all essential details.

After several trials and errors, we settled on the following prompt for document generation. While it's still a challenge to use the same prompt for all documentation, we made minor modifications to suit different situations:

I'm creating an SQL database documentation website, and I'd like you to help me with one of the pages that introduces the SQL syntax for GlueSQL.

1. Please provide the response content in the "markdown" format, so I can copy and paste it directly. Keep this constraint in mind while writing.
2. Regardless of the language I use, I need the content written in English.
3. I will provide some test case code written in the Rust language, which contains SQL examples. Please write the documentation based on these examples, but feel free to change the table names, column names, and data types as needed. Don't include any Rust related content or text in the response. all the response code example should be in plain SQL.
4. GlueSQL does not have the VARCHAR type. If you want to use that, please use TEXT instead. You don't need to mention this in the response.
5. Wrap the entire response text using <pre> and </pre> tags so I can copy all the content easily.

Now, I'd like you to write the following request:
SQL Statement - "INSERT"

Here's an example test code you can refer to:

test_case!(insert, async move {
run!(...

Generally, we used the template above, and copied and pasted the test code from our existing test-suite. We leveraged this method to harness our many tests to assist in the creation of the user manual. In the next section, we'll showcase a sample of the documentation generated in this manner. It's quite impressive.

Success Case: Automated User Manual of GlueSQL

Thanks to ChatGPT, the resulting INSERT document page can be viewed at the following link. It's important to note that we used ChatGPT 4 for this task. Version 3.5 wasn't quite up to the task, and using version 4 was the minimum requirement.

https://gluesql.org/docs/dev/sql-syntax/statements/data-manipulation/insert

INSERT Statement

The results were quite impressive. ChatGPT neatly categorized the test cases, explained the syntax, outlined constraints, and provided appropriate examples. It didn't stop there; it also skillfully recognized error test cases and incorporated them into the documentation, as shown below.

INSERT Statement

Isn't it amazing?

Future Plans: Fully Automating Documentation Generation

While the current documentation is far from perfect and there are many aspects that can be improved, we see great potential in this approach. We believe it's entirely possible to automate the process of writing this kind of document, and writing in general.

In the past, documents like user manuals required a great deal of effort to maintain once they were written. If a document contained real code examples, verifying that the code still worked was often a tedious task. With the ability to automatically generate documentation as we have done here, these issues are no longer problematic.

Previously, you would have to write tests and then also document them separately. If you had to support multiple languages, that would be an additional task. With a tool like ChatGPT, you can automate all of this. All a developer has to do is write the tests. This alone can be sufficient. You can generate documents automatically based on the tests. Eventually, we can even support automatically translating these documents into multiple languages.

The GlueSQL project repository is currently hosted on GitHub and makes good use of various GitHub Actions. We envision a GitHub Action that automatically regenerates a document corresponding to a test when a user modifies the test and raises a Pull Request. Another GitHub Action could automatically translate updated documents into supported languages and create new Pull Requests. The possibilities are truly endless.

Not only will this help with document generation, but it will also provide clear guidelines for writing better test code. If we can automatically generate documents based on written tests, the quality of those documents can serve as an indicator of the quality of the tests themselves. This means that a document automation tool can play the role of a good reviewer for tests. It can greatly reduce the time and effort required for painstakingly reviewing the quality of each test. Developers can also write tests without pressure, evaluate their test code by looking at the generated document, and improve it.

Furthermore, multi-language support becomes a breeze. In my personal experience as a software engineer over the past decade, developing various products such as games, web services, and applications, I often needed to support multiple languages. Each time, there was no definite solution. The optimal approach varied depending on the situation, and there were many things to consider when entrusting translations, such as effectively communicating the context of the target service to the translator. Moreover, regularly updating content and having it retranslated into various languages was a very tedious process. While I tried to automate as much as possible by creating various tools, I was never fully satisfied. I believe ChatGPT can completely solve these issues. If there is a need to provide project-specific context, all you need to do is prepare a prompt in advance. Instead of having to rely on and wait for professional translators, we can now entrust this task to ChatGPT, and we only need a few people to review the translated content.

We are nearing a world where documentation is no longer a burden for developers.

Conclusion: The Value of Test-Driven Documentation

The use of ChatGPT to generate documentation has proven a significant step forward in the GlueSQL user manual creation process. Through test-driven documentation, we've managed to automate a substantial part of the manual creation process, saving time and effort, and increasing accuracy.

Moreover, this process has unveiled a new potential for documentation: the possibility of fully automating document generation. We've seen that quality tests can become quality documentation with the help of AI, leading to more efficient workflows and possibly better test code as a result.

The journey doesn't stop here. We envision leveraging this capability further to auto-translate our documents into multiple languages, making our product more accessible to a global audience.

As we progress, we hope that our experience can inspire other developers to explore and embrace the benefits of AI-generated, test-driven documentation. It's not just about saving time—it's about improving the way we work, communicate, and share knowledge.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/blog/tags/database/index.html b/docs/0.16.0/blog/tags/database/index.html new file mode 100644 index 00000000..668e7fdd --- /dev/null +++ b/docs/0.16.0/blog/tags/database/index.html @@ -0,0 +1,30 @@ + + + + + +3 posts tagged with "database" | GlueSQL + + + + + +
+

3 posts tagged with "database"

View All Tags

· 14 min read
Taehoon Moon

Introduction

GlueSQL is a versatile database project designed for exceptional portability across a broad range of environments, from embedded systems and servers to web and mobile platforms. The core goal is to support diverse storage environments and manage various data types with a standard SQL approach.

Imagine handling files like CSV, JSONL, and Parquet, or transforming key-value or NoSQL databases such as RocksDB, Redis, and MongoDB into SQL-supporting databases—all feasible with GlueSQL. It can also operate with storages supported in web browsers.

GlueSQL's essential feature is providing a management layer for these diverse storage scenarios without requiring data migration. The broader aim is to facilitate portability of GlueSQL to any environment supporting read or read-write operations. This extends to APIs like GitHub, or messengers like Discord or Slack.

GlueSQL supports both structured and unstructured data and is written in Rust for compatibility with various environments. While portability is its core value, the emphasis is on creating an intuitive, comfortable development environment for easy custom storage implementation.

Ultimately, GlueSQL aims to significantly reduce the cost, time, and complexity of developing new databases. By leveraging GlueSQL for the parser, planner, and execution layer, developers can focus on creating specific storage implementations, leading to a more convenient query interface like SQL for many environments.

The Problem: Why Reinvent the Database?

Despite the numerous database implementations that currently exist, the emergence of new databases continues. The primary reason behind this trend is our need for databases for a broad spectrum of distinct purposes. For instance, new databases are surfacing that are specifically optimized for Large Language Models (LLMs) like ChatGPT. The range is wide and diverse, encompassing embedded databases, OLAP for data analysis, OLTP databases optimized for online transactions, databases specialized for time-series data processing, and many more.

With such varied requirements, we find ourselves in constant need of fresh databases. However, constructing a database from scratch is a monumental task. It necessitates defining a query interface for handling the database and implementing a corresponding parser. Moreover, a separate execution layer for running operations must be built. Also, the planning layer, which is responsible for devising execution strategies, is a vital aspect of this process. Let's not forget about the critical storage layer that physically reads and stores the data. In a nutshell, there's a daunting amount of work involved in developing a new database.

Given these circumstances, it's understandable why numerous emerging databases resort to high pricing structures—they need immediate revenue to offset continuous development costs.

But the story doesn't end here. Query interfaces like SQL are indeed useful for serious tasks, but they also provide excellent utility for handling simple log files such as CSV, JSONL, Parquet, and even for utilizing REST APIs for various applications. The issue arises when a complex query interface needs to be provided even for these lighter storage requirements—it necessitates a development process almost identical to building a sophisticated database. Implementing an entire parser and execution layer just to add SQL support to an existing service can seem like an excessive burden.

Whether it's a simple storage environment or a serious task, the key lies in the storage layer, which involves the actual reading and storing of data. So, what if developers focused on implementing these storage mechanisms while the remaining parts could be handled using existing libraries? This is the role that GlueSQL aspires to play.

The Vision of GlueSQL

The GlueSQL project aims to offer a unified query interface for various environments. The goal is to allow anyone to port and use SQL and GlueSQL's proprietary query builder, the AST Builder, in any desired environment. This could range from key-value databases, serious NoSQL databases, log files, and even REST API services. Essentially, if a service supports reading or read-writing data, regardless of the data type, it can readily support a complex query interface via GlueSQL.

Presently, the GlueSQL project itself directly supports a few storage types as reference storages. These include in-memory storage for non-persistent data handling, sled storage, which is a key-value database written in Rust, JSON storage for handling JSON and JSONL files, and a storage that ports SQL to the web browser's IndexedDB. While the GlueSQL Team is primarily developing these, the aim is to allow anyone to create such custom storages for a wide array of purposes, thus enabling them to assemble the database of their choosing.

Imagine using GlueSQL's SQL and AST Builder everywhere, with the simple method of swapping out storages to operate in diverse settings. It could significantly reduce software development costs. Developers wouldn't need to learn the different usage methods for each database. Instead, they could focus solely on implementing business logic using the same interface.

Our vision is to reduce database development costs by 10 times, or even more than 20 times. We aim to gather diverse database creators under the GlueSQL banner, making it the go-to solution for cost-effective database development.

Benefits to Database Users: Unifying Query Interfaces, Streamlining Software Development, and Reducing Costs

From the perspective of the users who engage with databases, there has always been the burden of learning different interfaces to interact with each database. The approach required to work with Redis is different from that necessary for MongoDB. Likewise, handling SQL databases necessitates using SQL. Although SQL databases generally use a common SQL, the SQL they support can considerably vary when examined in detail.

Naturally, there are legitimate reasons for such differences. Each database focuses on different areas, and to cater to specialized functionalities, they incorporate dedicated interface mechanisms. However, not all application development needs to utilize these database-specific core special functionalities.

Let's look at a couple of examples:

Suppose you're developing a back-end application that uses MySQL as the database and Redis for caching. Due to the vast differences in handling SQL databases and Redis, you would have to develop using different methods when storing data.

Here's another scenario: +Imagine you're implementing a data migration pipeline between various databases and log files. Let's say you're transferring Parquet to Redis or MongoDB. In this case, you would need to convert data using different methods for each, all of which would be a cumbersome process.

In both of the above examples, GlueSQL can directly address and solve the issues. It offers the convenience of a uniform query interface to deal with these matters. In certain scenarios, even the construction of a data pipeline can potentially be solved with a single SQL query, thanks to GlueSQL.

Benefits to Database Developers: Drastically Lowering Development Costs and Simplifying the Creation of Purpose-Built Databases

If you want to support SQL in the desired environment, using GlueSQL essentially requires you to implement an interface for Storage. There's no need to support all functionalities from the beginning. You can start lightly, choosing and implementing storage features suitable for the environment you want to create. To facilitate this, GlueSQL also provides a library in the form of a test suite to easily validate the storage you've implemented.

Lowering development costs in this way will enable a broader range of developers to support the GlueSQL query interface. As more developers join, a significant synergy can be generated. Designing a query interface from scratch involves a great deal of work, including planning and supporting the interface for different target programming languages.

However, despite all this hard work, it is not easy to attract database users accustomed to different methods.

Consider that the SQL and AST Builder provided by GlueSQL are already securing numerous users. This eliminates the need for efforts to promote a newly planned query interface. Over the years, many new databases have emphasized compatibility with PostgreSQL or MySQL for similar reasons. As GlueSQL places a strong emphasis on portability in its query interface planning, it allows for more flexible configuration according to the desired situation. Through the AST Builder, it also eliminates the cost of porting to different languages.

For many database developers, using GlueSQL can be an optimal choice, as it can save costs and quickly secure users.

Let me mention one more thing: what's convenient for humans... could be applied to AI as well. Rather than making AI write automation code using different databases, providing a common query interface can be much more efficient.

The Future with GlueSQL

GlueSQL has been and will continue to improve and develop new features to enable portability in various environments. Thanks to the schemaless data support added last year, it is now possible to handle both structured data with schema and unstructured data like JSON simultaneously. This has significantly increased the range of storage environments that can be supported.

One of the key features added last year was the AST Builder. This feature allowed us to escape the confines of SQL and provide an interface for comfortably handling data in the programming languages used for development.

Of course, improving existing features is extremely important, and there are many new features to be added. As a major development plan this year, we aim to develop features to effectively attach GlueSQL to NoSQL databases with their own planners and execution layers. The GlueSQL query planner, currently at a basic level, will see significant changes this year. With the expansion of this planner, not only NoSQL databases but also other SQL databases could be supported without sacrificing performance using GlueSQL.

The synergy that arises from the combination of different databases is a significant bonus in this process.

The Journey of the GlueSQL Team

The GlueSQL project was first conceived in the fall of 2019, and since then we have been developing it continuously. Personally, I have created various products in a variety of environments, including game development, backend server, and frontend development over the past decade. The experience gained through this process was a major motivation to start the GlueSQL project.

To put it grandly, the inconveniences felt while using different databases in various environments were a major motivation, wouldn't you say?

The start was actually a bit simple. Around 2019, I was mainly doing web front-end development. However, the lack of a structured database for state management and internal data processing made it very uncomfortable, especially since I couldn't use SQL databases and the like. So I started to lightly create an SQL database that could run on a web browser. Also, I wanted to use Rust, but after failing to introduce it at the company I was working for at the time, I decided to use it in my own project.

But as I started developing, my dreams grew significantly. Beyond a SQL database that simply operates on a web browser, I started envisioning a database that fits the name "Glue", one that can easily be ported to various environments, and I continue that journey to this day.

Whether I took the database project too lightly, or because the features I wanted kept increasing, the content to be developed kept expanding. As a result, I ended up investing full time in the GlueSQL project development for over three years. For a year in between, I even juggled full-time software engineering work alongside GlueSQL development. Currently, I'm back to developing the GlueSQL project full time, alongside various part-time contributors.

Now, we're getting very close to the starting point of the picture I wanted to create through GlueSQL, and thankfully, with contributors joining me, I am not alone.

The Sustainability and Business Aspect of GlueSQL

I believe that what we create through GlueSQL will make a great contribution to the world and make many software engineers happy. This gives me immense strength to continue developing even in difficult situations. However, we cannot accomplish everything with pure passion alone. As much as the GlueSQL project can make a significant contribution, I also see it as holding great business value.

The business strategy of GlueSQL may be somewhat different from other databases. We distribute the project itself as open source under the Apache-2.0 license, so that anyone can use it fully, and we do not consider pricing methods such as restricting features to the storages we support. In fact, if there is any player who can do it better, there's no way to prevent them from taking the GlueSQL project and making it their own.

But we believe that GlueSQL has great potential in this regard. Anyone can participate and they are free to distribute their own storage in the way they want, whether it's open source, private, or commercial. This eliminates the need to create something to replace the GlueSQL project. We aim to prevent the need to recreate the wheel that we provide using GlueSQL.

Moreover, our GlueSQL team seeks to continually expand our group of developers and companies working with us. During this development process, while they can certainly implement everything on their own, there is also no reason not to collaborate with our GlueSQL Team, especially for databases like NoSQL that have their own planners and execution layers. If you have a REST API and want to enhance convenience through SQL support, you can do it yourself or you can collaborate with us.

In addition, for some storages, we can also participate as players in the same position as other custom storage developers. We plan to expand the GlueSQL ecosystem in various ways, such as technical support and storage development.

We are finally ready to provide GlueSQL to users at the production level. We are accelerating the development of GlueSQL. If you are a company interested in storage development like SQL support, or if you resonate with our vision and want to join us, please contact us at taehoon@gluesql.com.

Conclusion

The continued emergence of new databases is driven by the demand for diverse and specialized databases, such as those optimized for Large Language Models (LLMs) and databases catering to unique requirements, like embedded databases, OLAP, OLTP, and time-series data processing. However, developing a new database from scratch is a significant undertaking, requiring extensive work, which often results in high costs.

GlueSQL presents a solution to this challenge by providing a unified query interface that can be ported across various environments, from key-value databases, NoSQL databases, log files, to REST APIs. It allows anyone to create custom storages, reducing the need for developers to build entirely new databases and to learn different usage methods for each database. Instead, they can focus on implementing their business logic using the same interface.

From a user perspective, GlueSQL offers the convenience of a unified query interface, easing the burden of learning different interfaces for each database. This simplification of interface use can also extend to AI, potentially enhancing the efficiency of AI automation.

GlueSQL's development plan includes significant enhancements to its query planner and aims to enable effective attachment of GlueSQL to NoSQL databases. The synergy of combining different databases is a valuable bonus in this process.

Since its inception in the fall of 2019, the GlueSQL team has continuously developed the project, driven by the desire to mitigate the inconveniences encountered while using different databases in various environments. The journey has been a rewarding one, with the GlueSQL project now at a point where it closely resembles the envisioned product.

GlueSQL, distributed under the Apache-2.0 license, is free for anyone to use and adapt. While the GlueSQL team welcomes collaboration with other developers and companies, they also see significant potential for the project as a business venture. The team is working to expand the GlueSQL ecosystem through a variety of initiatives, including technical support and storage development.

With GlueSQL now sufficiently prepared for practical applications, the team invites companies interested in storage development or those who share their vision to join them in their journey of revolutionizing database development.

· 10 min read
Taehoon Moon

Introduction: GlueSQL and Test-Driven Documentation

Recently, the GlueSQL project reached a significant milestone with the release of version 0.14. This new version brings a host of fresh features to the table, yet one of the most notable changes is in the realm of documentation. For the first time, we're proud to announce the launch of our official documentation website. Interested readers can explore the full range of user manuals at https://gluesql.org/docs.

Prior to this update, the only way to navigate GlueSQL was by manually inspecting the test code within the test suite. With the recent release, however, a comprehensive user manual has been made public to facilitate a more user-friendly experience. We hope that this new addition will prove beneficial to a broad spectrum of users.

The task of compiling an entire database manual in one go was daunting due to the sheer volume of content required. Surprisingly, this process turned out to be smoother than initially anticipated, largely due to the invaluable aid of ChatGPT, which was instrumental in automating much of the document creation. Specifically, around 80% of the SQL Syntax section was generated using this tool.

This remarkable feat was only possible due to the solid foundation of test codes previously established in GlueSQL. In this article, we'll share how we managed to leverage ChatGPT in such a unique way. Based on our recent experience of crafting documents grounded in testing, we've begun to consider the possibility of entirely automating document creation, save for the initial stages.

Along with sharing our journey so far, we will also reveal our plans for future test-based automation of documentation within GlueSQL.

Test Codes and Documentation

The GlueSQL project has placed a significant emphasis on writing test codes. This might be a given for a database project; however, the thoroughness of our approach is evident from our line coverage of nearly 99% for core codes. While we devoted considerable effort to creating these test codes, our primary focus has always been on a different aspect: ensuring that anyone can quickly grasp the content of the tests and easily add new ones.

The intent here is to empower newcomers to GlueSQL to understand the functionality of the software solely by examining integration tests, even in the absence of a user manual.

The integration tests for GlueSQL can be found in the test-suite workspace. For example, here's an excerpt of the test code for the INSERT statement:

test_case!(insert, async move {
run!(
"
CREATE TABLE Test (
id INTEGER DEFAULT 1,
num INTEGER NULL,
name TEXT NOT NULL,
);"
);

test! {
name: "basic insert - single item",
sql: "INSERT INTO Test (id, num, name) VALUES (1, 2, 'Hi boo');",
expected: Ok(Payload::Insert(1))
};


test! {
sql: "INSERT INTO Test VALUES(17, 30, 'Sullivan');",
expected: Ok(Payload::Insert(1))
};

test! {
sql: "INSERT INTO Test (num, name) VALUES (28, 'Wazowski');",
expected: Ok(Payload::Insert(1))
};

test! {
sql: "SELECT * FROM Test;",
expected: Ok(select!(
id | num | name;
I64 | I64 | Str;
1 2 "Hi boo".to_owned();
3 9 "Kitty!".to_owned();
2 7 "Monsters".to_owned();
17 30 "Sullivan".to_owned();
1 28 "Wazowski".to_owned()
))
};

// ...
});

Despite being written in Rust, these test cases are designed to be comprehensible, even to those unfamiliar with the language. Each test is a complete scenario from start to finish, and the results of each operation are readily observable.

Given that identifying results from SELECT operations in the form of Rust enums and structs can be challenging, we actively utilized macros such as select! and select_with_null!. We've composed the test cases to demonstrate that the INSERT statement can handle a wide range of cases, including specifying all columns, omitting some, or omitting all.

test! {
sql: "INSERT INTO Test (id, num) VALUES (1, 10);",
expected: Err(InsertError::LackOfRequiredColumn("name".to_owned()).into())
};

The tests also include scenarios for expected faulty inputs, indicating the error returns in these situations.

By organizing the tests in this manner, we aim to make it easy for anyone to read and write tests. Our goal was for these tests to serve as "documentation" for GlueSQL contributors. At the time we were writing these tests, we didn't anticipate that they could actually become documentation themselves. But we've come to realize that they have extraordinary potential.

Leveraging ChatGPT

When we first embarked on writing the User Manual, we were overwhelmed by the sheer volume of content we had to generate. Around the same time, ChatGPT was gaining prominence, and we thought it might be worth trying out, if only to lighten our load slightly.

To our surprise, ChatGPT exceeded our expectations. If the test codes were well written, it was capable of automatically crafting an exceptional document based on them, capturing all essential details.

After several trials and errors, we settled on the following prompt for document generation. While it's still a challenge to use the same prompt for all documentation, we made minor modifications to suit different situations:

I'm creating an SQL database documentation website, and I'd like you to help me with one of the pages that introduces the SQL syntax for GlueSQL.

1. Please provide the response content in the "markdown" format, so I can copy and paste it directly. Keep this constraint in mind while writing.
2. Regardless of the language I use, I need the content written in English.
3. I will provide some test case code written in the Rust language, which contains SQL examples. Please write the documentation based on these examples, but feel free to change the table names, column names, and data types as needed. Don't include any Rust related content or text in the response. all the response code example should be in plain SQL.
4. GlueSQL does not have the VARCHAR type. If you want to use that, please use TEXT instead. You don't need to mention this in the response.
5. Wrap the entire response text using <pre> and </pre> tags so I can copy all the content easily.

Now, I'd like you to write the following request:
SQL Statement - "INSERT"

Here's an example test code you can refer to:

test_case!(insert, async move {
run!(...

Generally, we used the template above, and copied and pasted the test code from our existing test-suite. We leveraged this method to harness our many tests to assist in the creation of the user manual. In the next section, we'll showcase a sample of the documentation generated in this manner. It's quite impressive.

Success Case: Automated User Manual of GlueSQL

Thanks to ChatGPT, the resulting INSERT document page can be viewed at the following link. It's important to note that we used ChatGPT 4 for this task. Version 3.5 wasn't quite up to the task, and using version 4 was the minimum requirement.

https://gluesql.org/docs/dev/sql-syntax/statements/data-manipulation/insert

INSERT Statement

The results were quite impressive. ChatGPT neatly categorized the test cases, explained the syntax, outlined constraints, and provided appropriate examples. It didn't stop there; it also skillfully recognized error test cases and incorporated them into the documentation, as shown below.

INSERT Statement

Isn't it amazing?

Future Plans: Fully Automating Documentation Generation

While the current documentation is far from perfect and there are many aspects that can be improved, we see great potential in this approach. We believe it's entirely possible to automate the process of writing this kind of document, and writing in general.

In the past, documents like user manuals required a great deal of effort to maintain once they were written. If a document contained real code examples, verifying that the code still worked was often a tedious task. With the ability to automatically generate documentation as we have done here, these issues are no longer problematic.

Previously, you would have to write tests and then also document them separately. If you had to support multiple languages, that would be an additional task. With a tool like ChatGPT, you can automate all of this. All a developer has to do is write the tests. This alone can be sufficient. You can generate documents automatically based on the tests. Eventually, we can even support automatically translating these documents into multiple languages.

The GlueSQL project repository is currently hosted on GitHub and makes good use of various GitHub Actions. We envision a GitHub Action that automatically regenerates a document corresponding to a test when a user modifies the test and raises a Pull Request. Another GitHub Action could automatically translate updated documents into supported languages and create new Pull Requests. The possibilities are truly endless.

Not only will this help with document generation, but it will also provide clear guidelines for writing better test code. If we can automatically generate documents based on written tests, the quality of those documents can serve as an indicator of the quality of the tests themselves. This means that a document automation tool can play the role of a good reviewer for tests. It can greatly reduce the time and effort required for painstakingly reviewing the quality of each test. Developers can also write tests without pressure, evaluate their test code by looking at the generated document, and improve it.

Furthermore, multi-language support becomes a breeze. In my personal experience as a software engineer over the past decade, developing various products such as games, web services, and applications, I often needed to support multiple languages. Each time, there was no definite solution. The optimal approach varied depending on the situation, and there were many things to consider when entrusting translations, such as effectively communicating the context of the target service to the translator. Moreover, regularly updating content and having it retranslated into various languages was a very tedious process. While I tried to automate as much as possible by creating various tools, I was never fully satisfied. I believe ChatGPT can completely solve these issues. If there is a need to provide project-specific context, all you need to do is prepare a prompt in advance. Instead of having to rely on and wait for professional translators, we can now entrust this task to ChatGPT, and we only need a few people to review the translated content.

We are nearing a world where documentation is no longer a burden for developers.

Conclusion: The Value of Test-Driven Documentation

The use of ChatGPT to generate documentation has proven a significant step forward in the GlueSQL user manual creation process. Through test-driven documentation, we've managed to automate a substantial part of the manual creation process, saving time and effort, and increasing accuracy.

Moreover, this process has unveiled a new potential for documentation: the possibility of fully automating document generation. We've seen that quality tests can become quality documentation with the help of AI, leading to more efficient workflows and possibly better test code as a result.

The journey doesn't stop here. We envision leveraging this capability further to auto-translate our documents into multiple languages, making our product more accessible to a global audience.

As we progress, we hope that our experience can inspire other developers to explore and embrace the benefits of AI-generated, test-driven documentation. It's not just about saving time—it's about improving the way we work, communicate, and share knowledge.

· 11 min read
Taehoon Moon

Introduction

The divide between SQL and NoSQL databases has often presented challenges in database management. GlueSQL, a unique database maker library, aims to blur this boundary, providing a versatile tool for handling these two distinct types of databases.

In this article, we explore how GlueSQL navigates the features of SQL and NoSQL databases, offering an integrated solution that promotes flexibility and efficiency. With its ability to unify disparate database types, GlueSQL heralds a new age of adaptable database creation and management.

The Interface Perspective: SQL & AST Builder

When we talk about SQL databases, it's almost a given that they support SQL - the standard query language. Although there are slight variations between databases, the convenience of using a similar SQL language across multiple databases cannot be overstated. However, from a software engineer's perspective, there's room for improvement. In most software development scenarios, a specific programming language is used. SQL is a separate language, which can cause friction when integrating it into your software. As a result, rather than using raw SQL, many developers employ query builders or ORMs to manipulate SQL conveniently using their preferred programming language. Although it's not efficient to generate SQL using a query builder and then parse it again in the database, it's a practical and effective choice.

On the other hand, NoSQL databases offer different mechanisms. Some of them have their own language similar to SQL, but most provide an interface library developed specifically for each programming language. While SQL databases rely on external query builder libraries to provide an interface for each programming language, NoSQL databases mostly develop and offer these libraries themselves. If we discount the convenience of SQL language, this is one of the major factors that make NoSQL databases more comfortable to use. Since query builder libraries supporting SQL databases often cater to multiple SQL databases, they are limited in fully supporting unique features of each database. NoSQL databases, on the other hand, can freely manage their interface libraries without these restrictions.

Providing a query interface for each programming language is not a fundamental difference between SQL and NoSQL, but we generally accept it implicitly.

Let's see what happens if we break down this boundary, using GlueSQL as an example. As you can see from the SQL postfix, GlueSQL supports SQL and can be classified as an SQL database.

CREATE TABLE Glue (id INTEGER, name TEXT);

INSERT INTO Glue VALUES (1, "hello"), (2, "gluesql");

SELECT * FROM Glue WHERE id = 1;

However, GlueSQL also supports its own query builder, like a NoSQL database. +(Currently, only Rust is supported, but we're working on adding support for other languages.)

table("Glue")
.create_table()
.add_column("id INTEGER")
.add_column("name TEXT")
.execute(glue)

table("Glue")
.insert()
.values(vec![
vec![num(1), text("hello")],
vec![num(2), text("gluesql")],
])
.execute(glue)
.await;

table("Glue")
.select()
.filter(col("id").eq(1))
.execute(glue)
.await;

Let's reconsider the implicit distinction between SQL and NoSQL. GlueSQL indeed supports SQL, but it also officially develops and offers its own query builder. This query builder is not a secondary tool for SQL. While most SQL query builder libraries ultimately generate SQL strings, GlueSQL's builder directly creates an AST (Abstract Structure Tree) that is used for execution within GlueSQL. Hence, we call it the AST Builder. This means SQL and the AST Builder are two equally supported interfaces in GlueSQL.

This also offers an additional advantage:

table("Glue")
.select()
// 1.
.filter(col("id").eq(1))
// 2.
.filter("id = 1")
.execute(glue)
.await;

Because GlueSQL already supports SQL, not only can you use the custom interface in the AST Builder, but you can also use familiar SQL syntax in part. Whether you use col("id").eq(1) or "id = 1", you can use it in the way you prefer. The AST Builder interface, although initially unfamiliar, allows a gradual migration similar to writing SQL for your convenience.

Thus, we've dismantled one of the implicit distinctions between SQL and NoSQL. However, it's more of an implicit differentiation than a fundamental one. There are more significant design differences that we'll explore next.

Structured & Unstructured Data

In this section, we'll discuss how SQL and NoSQL handle data. SQL generally deals with structured data, and recently, it's been made to support semi-structured data as well. On the other hand, NoSQL supports schemaless, unstructured data. Then, we'll explain in detail how GlueSQL handles these two types of data. The last part of this section will provide a segue into the next section where we'll discuss the decomposition of database functions.

When talking about SQL databases, one aspect is usually considered together: SQL databases have a defined schema.

CREATE TABLE Foo (
id INTEGER,
name TEXT,
rate FLOAT NULL
);

However, these days, SQL databases tend to support semi-structured data types, such as LIST or JSON. But, supporting completely schemaless, unstructured data is a different matter. SQL databases typically require a minimum schema.

What about NoSQL databases? As NoSQL databases vary significantly, we can't make definitive statements. But let's consider a typical document database like MongoDB. Unlike SQL databases, it doesn't enforce a schema. Essentially, you can insert any form of data directly. Often, NoSQL databases support schemaless data, but they lack features that enforce a schema like SQL. They generally support structure via validation methods, rather than structured access.

Is there no choice but to distinguish between structured data and unstructured, schemaless data so clearly? GlueSQL is being developed with the goal of being adaptable in various environments. Being forced to choose regarding this schema constraint was quite inconvenient. We started pondering if we couldn't benefit from both aspects - supporting both schema and schemaless data simultaneously, and we eventually found the answer. Let's look at how GlueSQL currently solves this issue through familiar SQL examples.

CREATE TABLE Names (id INTEGER, name TEXT);
INSERT INTO Names VALUES (1, 'glue'), (2, 'sql');

You can create a regular table with a schema like this. But GlueSQL's choice for creating a schemaless table is as follows:

CREATE TABLE Logs;
INSERT INTO Logs VALUES
('{ "id": 1, "value": 30 }'),
('{ "id": 2, "rate": 3.0, "list": [1, 2, 3] }'),
('{ "id": 3, "rate": 5.0, "value": 100 }');

It creates a table without column definitions! If you do this, GlueSQL recognizes the table as schemaless and processes it internally.

SELECT id, rate, list[0] FROM Logs WHERE id = 2;

Although the way to create the table was a bit special, using it isn't much different from the regular SQL SELECT statement. Not only can you differentiate between schema and schemaless when creating tables, but you can also use them interchangeably!

SELECT * FROM Names JOIN Logs ON Names.id = Logs.id;
/*
| id | list | name | rate | value |
|----|---------|------|------|-------|
| 1 | | glue | | 30 |
| 2 |[1, 2, 3]| sql | 3 | |
*/

Here's an example of querying data by INNER JOINing the Names table, which has a schema, and the Logs table, which is schemaless. GlueSQL has resolved this problem by allowing the internal execution layer to handle both vector-type data, for cases where each row has a defined schema, and map-type data for schemaless cases.

Thanks to this, the variety of storage that can be supported through GlueSQL has expanded significantly. If there were previously limitations to supporting NoSQL databases that support schemaless data, that is no longer the case. The reference storage where you can directly experience this schemaless data support is JSON Storage. It offers features that allow you to deal directly with unstructured data like JSON using GlueSQL.

If GlueSQL starts from the perspective of an SQL database and expands, by providing the AST Builder directly, it once blurs the boundary, and by supporting unstructured data simultaneously, it knocks down the boundary once more. How do you like it?

Decomposing Database Functionality: Breaking Down SQL and NoSQL Features

The distinction between SQL and NoSQL is not just about whether they support unstructured data. Of course, there are examples like unstructured data, which is mainly supported only in NoSQL, but in many cases, SQL databases tend to support more diverse and complex queries. NoSQL often gains other advantages in exchange for reducing the range of query support provided by SQL databases.

GlueSQL is ambitious. It has devised a rather interesting method to support all of this through SQL and the AST Builder, with the same interface. When we usually say SQL database, it implicitly assumes that a lot of features have been fully implemented. Create tables by specifying a schema, modify schemas with "alter table", support both clustered and non-clustered indexes, and support transactions. And there's so much more. But the functionality that is naturally supported in SQL databases may not be natural in other environments.

Let's think about JSON Storage. GlueSQL's JSON Storage allows you to handle JSON, JSONL files using SQL and the AST Builder. This JSON Storage does not support atomic operations or transactions. Of course, it would be great if it did, but implementing and executing them would be a significant performance burden. In most cases, when you want to simply browse and handle JSONL files, the overhead caused by transactions can be an unnecessary burden. In this case, you want to handle JSON, JSONL files using SQL, but you don't necessarily need transactions.

To meet the requirements of these diverse environments, GlueSQL has separated the functionality of what we usually call an SQL database into multiple independent interfaces. +Store, StoreMut, AlterTable, Transaction, .. +These are just a few of the various storage interfaces that GlueSQL currently supports. +The way it works can be summarized like this: +If you implement Store, you can use SELECT. +And if you implement both Store and StoreMut, you can support quite a number of basic SQL statements including SELECT. +You can manage tables with CREATE TABLE, DROP TABLE, and handle data using INSERT, UPDATE, DELETE statements. +If you only need to retrieve data, you only need to implement Store. +If you want to support the ALTER TABLE statement, you can additionally implement the AlterTable interface. +The Transaction interface works the same way. +The interesting part is that, except for Store and StoreMut, all other storage interfaces can be implemented independently. GlueSQL allows you to choose and implement only the features you need. +And it's not just about providing interfaces. It also provides integration tests suitable for each situation to verify what you have implemented. You just need to implement the interface and import the corresponding test case for verification.

In addition to supporting both structured and unstructured data simultaneously, GlueSQL provides the ability to divide the functionality of a database into multiple independent features and selectively implement them. This allows GlueSQL to be ported to a wide variety of environments without any burden.

Conclusion

GlueSQL, while serving as a database that provides its own reference storage, is fundamentally a library designed to simplify the creation of databases. One of the substantial challenges GlueSQL had to overcome in order to support a diverse array of environments was to address the distinctive features that separate conventional SQL databases from NoSQL databases. GlueSQL achieved this through several innovative approaches, managing to support both categories simultaneously despite their significantly different characteristics.

It offers support for SQL alongside an AST Builder, and accommodates both structured and unstructured data. Additionally, it decomposes database functionalities into multiple independent features, allowing each environment to selectively implement the functionalities it requires.

These unique attributes enable GlueSQL to live up to its 'Glue' prefix by facilitating effortless porting across various environments. While we have been developing it for several years, there is still much ground to cover. However, the fact that we are now able to introduce it publicly attests to our successful technological validation and completion of a demonstrable level of implementation.

Through GlueSQL, we hope to provide developers with a unified query interface that can be customized according to their needs, thereby enabling them to produce efficient products more effortlessly. There's a promising future ahead for GlueSQL, and we look forward to its contributions to the technology community.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/blog/tags/documentation/index.html b/docs/0.16.0/blog/tags/documentation/index.html new file mode 100644 index 00000000..5147d386 --- /dev/null +++ b/docs/0.16.0/blog/tags/documentation/index.html @@ -0,0 +1,17 @@ + + + + + +One post tagged with "Documentation" | GlueSQL + + + + + +
+

One post tagged with "Documentation"

View All Tags

· 10 min read
Taehoon Moon

Introduction: GlueSQL and Test-Driven Documentation

Recently, the GlueSQL project reached a significant milestone with the release of version 0.14. This new version brings a host of fresh features to the table, yet one of the most notable changes is in the realm of documentation. For the first time, we're proud to announce the launch of our official documentation website. Interested readers can explore the full range of user manuals at https://gluesql.org/docs.

Prior to this update, the only way to navigate GlueSQL was by manually inspecting the test code within the test suite. With the recent release, however, a comprehensive user manual has been made public to facilitate a more user-friendly experience. We hope that this new addition will prove beneficial to a broad spectrum of users.

The task of compiling an entire database manual in one go was daunting due to the sheer volume of content required. Surprisingly, this process turned out to be smoother than initially anticipated, largely due to the invaluable aid of ChatGPT, which was instrumental in automating much of the document creation. Specifically, around 80% of the SQL Syntax section was generated using this tool.

This remarkable feat was only possible due to the solid foundation of test codes previously established in GlueSQL. In this article, we'll share how we managed to leverage ChatGPT in such a unique way. Based on our recent experience of crafting documents grounded in testing, we've begun to consider the possibility of entirely automating document creation, save for the initial stages.

Along with sharing our journey so far, we will also reveal our plans for future test-based automation of documentation within GlueSQL.

Test Codes and Documentation

The GlueSQL project has placed a significant emphasis on writing test codes. This might be a given for a database project; however, the thoroughness of our approach is evident from our line coverage of nearly 99% for core codes. While we devoted considerable effort to creating these test codes, our primary focus has always been on a different aspect: ensuring that anyone can quickly grasp the content of the tests and easily add new ones.

The intent here is to empower newcomers to GlueSQL to understand the functionality of the software solely by examining integration tests, even in the absence of a user manual.

The integration tests for GlueSQL can be found in the test-suite workspace. For example, here's an excerpt of the test code for the INSERT statement:

test_case!(insert, async move {
run!(
"
CREATE TABLE Test (
id INTEGER DEFAULT 1,
num INTEGER NULL,
name TEXT NOT NULL,
);"
);

test! {
name: "basic insert - single item",
sql: "INSERT INTO Test (id, num, name) VALUES (1, 2, 'Hi boo');",
expected: Ok(Payload::Insert(1))
};


test! {
sql: "INSERT INTO Test VALUES(17, 30, 'Sullivan');",
expected: Ok(Payload::Insert(1))
};

test! {
sql: "INSERT INTO Test (num, name) VALUES (28, 'Wazowski');",
expected: Ok(Payload::Insert(1))
};

test! {
sql: "SELECT * FROM Test;",
expected: Ok(select!(
id | num | name;
I64 | I64 | Str;
1 2 "Hi boo".to_owned();
3 9 "Kitty!".to_owned();
2 7 "Monsters".to_owned();
17 30 "Sullivan".to_owned();
1 28 "Wazowski".to_owned()
))
};

// ...
});

Despite being written in Rust, these test cases are designed to be comprehensible, even to those unfamiliar with the language. Each test is a complete scenario from start to finish, and the results of each operation are readily observable.

Given that identifying results from SELECT operations in the form of Rust enums and structs can be challenging, we actively utilized macros such as select! and select_with_null!. We've composed the test cases to demonstrate that the INSERT statement can handle a wide range of cases, including specifying all columns, omitting some, or omitting all.

test! {
sql: "INSERT INTO Test (id, num) VALUES (1, 10);",
expected: Err(InsertError::LackOfRequiredColumn("name".to_owned()).into())
};

The tests also include scenarios for expected faulty inputs, indicating the error returns in these situations.

By organizing the tests in this manner, we aim to make it easy for anyone to read and write tests. Our goal was for these tests to serve as "documentation" for GlueSQL contributors. At the time we were writing these tests, we didn't anticipate that they could actually become documentation themselves. But we've come to realize that they have extraordinary potential.

Leveraging ChatGPT

When we first embarked on writing the User Manual, we were overwhelmed by the sheer volume of content we had to generate. Around the same time, ChatGPT was gaining prominence, and we thought it might be worth trying out, if only to lighten our load slightly.

To our surprise, ChatGPT exceeded our expectations. If the test codes were well written, it was capable of automatically crafting an exceptional document based on them, capturing all essential details.

After several trials and errors, we settled on the following prompt for document generation. While it's still a challenge to use the same prompt for all documentation, we made minor modifications to suit different situations:

I'm creating an SQL database documentation website, and I'd like you to help me with one of the pages that introduces the SQL syntax for GlueSQL.

1. Please provide the response content in the "markdown" format, so I can copy and paste it directly. Keep this constraint in mind while writing.
2. Regardless of the language I use, I need the content written in English.
3. I will provide some test case code written in the Rust language, which contains SQL examples. Please write the documentation based on these examples, but feel free to change the table names, column names, and data types as needed. Don't include any Rust related content or text in the response. all the response code example should be in plain SQL.
4. GlueSQL does not have the VARCHAR type. If you want to use that, please use TEXT instead. You don't need to mention this in the response.
5. Wrap the entire response text using <pre> and </pre> tags so I can copy all the content easily.

Now, I'd like you to write the following request:
SQL Statement - "INSERT"

Here's an example test code you can refer to:

test_case!(insert, async move {
run!(...

Generally, we used the template above, and copied and pasted the test code from our existing test-suite. We leveraged this method to harness our many tests to assist in the creation of the user manual. In the next section, we'll showcase a sample of the documentation generated in this manner. It's quite impressive.

Success Case: Automated User Manual of GlueSQL

Thanks to ChatGPT, the resulting INSERT document page can be viewed at the following link. It's important to note that we used ChatGPT 4 for this task. Version 3.5 wasn't quite up to the task, and using version 4 was the minimum requirement.

https://gluesql.org/docs/dev/sql-syntax/statements/data-manipulation/insert

INSERT Statement

The results were quite impressive. ChatGPT neatly categorized the test cases, explained the syntax, outlined constraints, and provided appropriate examples. It didn't stop there; it also skillfully recognized error test cases and incorporated them into the documentation, as shown below.

INSERT Statement

Isn't it amazing?

Future Plans: Fully Automating Documentation Generation

While the current documentation is far from perfect and there are many aspects that can be improved, we see great potential in this approach. We believe it's entirely possible to automate the process of writing this kind of document, and writing in general.

In the past, documents like user manuals required a great deal of effort to maintain once they were written. If a document contained real code examples, verifying that the code still worked was often a tedious task. With the ability to automatically generate documentation as we have done here, these issues are no longer problematic.

Previously, you would have to write tests and then also document them separately. If you had to support multiple languages, that would be an additional task. With a tool like ChatGPT, you can automate all of this. All a developer has to do is write the tests. This alone can be sufficient. You can generate documents automatically based on the tests. Eventually, we can even support automatically translating these documents into multiple languages.

The GlueSQL project repository is currently hosted on GitHub and makes good use of various GitHub Actions. We envision a GitHub Action that automatically regenerates a document corresponding to a test when a user modifies the test and raises a Pull Request. Another GitHub Action could automatically translate updated documents into supported languages and create new Pull Requests. The possibilities are truly endless.

Not only will this help with document generation, but it will also provide clear guidelines for writing better test code. If we can automatically generate documents based on written tests, the quality of those documents can serve as an indicator of the quality of the tests themselves. This means that a document automation tool can play the role of a good reviewer for tests. It can greatly reduce the time and effort required for painstakingly reviewing the quality of each test. Developers can also write tests without pressure, evaluate their test code by looking at the generated document, and improve it.

Furthermore, multi-language support becomes a breeze. In my personal experience as a software engineer over the past decade, developing various products such as games, web services, and applications, I often needed to support multiple languages. Each time, there was no definite solution. The optimal approach varied depending on the situation, and there were many things to consider when entrusting translations, such as effectively communicating the context of the target service to the translator. Moreover, regularly updating content and having it retranslated into various languages was a very tedious process. While I tried to automate as much as possible by creating various tools, I was never fully satisfied. I believe ChatGPT can completely solve these issues. If there is a need to provide project-specific context, all you need to do is prepare a prompt in advance. Instead of having to rely on and wait for professional translators, we can now entrust this task to ChatGPT, and we only need a few people to review the translated content.

We are nearing a world where documentation is no longer a burden for developers.

Conclusion: The Value of Test-Driven Documentation

The use of ChatGPT to generate documentation has proven a significant step forward in the GlueSQL user manual creation process. Through test-driven documentation, we've managed to automate a substantial part of the manual creation process, saving time and effort, and increasing accuracy.

Moreover, this process has unveiled a new potential for documentation: the possibility of fully automating document generation. We've seen that quality tests can become quality documentation with the help of AI, leading to more efficient workflows and possibly better test code as a result.

The journey doesn't stop here. We envision leveraging this capability further to auto-translate our documents into multiple languages, making our product more accessible to a global audience.

As we progress, we hope that our experience can inspire other developers to explore and embrace the benefits of AI-generated, test-driven documentation. It's not just about saving time—it's about improving the way we work, communicate, and share knowledge.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/blog/tags/gluesql/index.html b/docs/0.16.0/blog/tags/gluesql/index.html new file mode 100644 index 00000000..9172f50d --- /dev/null +++ b/docs/0.16.0/blog/tags/gluesql/index.html @@ -0,0 +1,18 @@ + + + + + +One post tagged with "gluesql" | GlueSQL + + + + + +
+

One post tagged with "gluesql"

View All Tags

· 14 min read
Taehoon Moon

Introduction

GlueSQL is a versatile database project designed for exceptional portability across a broad range of environments, from embedded systems and servers to web and mobile platforms. The core goal is to support diverse storage environments and manage various data types with a standard SQL approach.

Imagine handling files like CSV, JSONL, and Parquet, or transforming key-value or NoSQL databases such as RocksDB, Redis, and MongoDB into SQL-supporting databases—all feasible with GlueSQL. It can also operate with storages supported in web browsers.

GlueSQL's essential feature is providing a management layer for these diverse storage scenarios without requiring data migration. The broader aim is to facilitate portability of GlueSQL to any environment supporting read or read-write operations. This extends to APIs like GitHub, or messengers like Discord or Slack.

GlueSQL supports both structured and unstructured data and is written in Rust for compatibility with various environments. While portability is its core value, the emphasis is on creating an intuitive, comfortable development environment for easy custom storage implementation.

Ultimately, GlueSQL aims to significantly reduce the cost, time, and complexity of developing new databases. By leveraging GlueSQL for the parser, planner, and execution layer, developers can focus on creating specific storage implementations, leading to a more convenient query interface like SQL for many environments.

The Problem: Why Reinvent the Database?

Despite the numerous database implementations that currently exist, the emergence of new databases continues. The primary reason behind this trend is our need for databases for a broad spectrum of distinct purposes. For instance, new databases are surfacing that are specifically optimized for Large Language Models (LLMs) like ChatGPT. The range is wide and diverse, encompassing embedded databases, OLAP for data analysis, OLTP databases optimized for online transactions, databases specialized for time-series data processing, and many more.

With such varied requirements, we find ourselves in constant need of fresh databases. However, constructing a database from scratch is a monumental task. It necessitates defining a query interface for handling the database and implementing a corresponding parser. Moreover, a separate execution layer for running operations must be built. Also, the planning layer, which is responsible for devising execution strategies, is a vital aspect of this process. Let's not forget about the critical storage layer that physically reads and stores the data. In a nutshell, there's a daunting amount of work involved in developing a new database.

Given these circumstances, it's understandable why numerous emerging databases resort to high pricing structures—they need immediate revenue to offset continuous development costs.

But the story doesn't end here. Query interfaces like SQL are indeed useful for serious tasks, but they also provide excellent utility for handling simple log files such as CSV, JSONL, Parquet, and even for utilizing REST APIs for various applications. The issue arises when a complex query interface needs to be provided even for these lighter storage requirements—it necessitates a development process almost identical to building a sophisticated database. Implementing an entire parser and execution layer just to add SQL support to an existing service can seem like an excessive burden.

Whether it's a simple storage environment or a serious task, the key lies in the storage layer, which involves the actual reading and storing of data. So, what if developers focused on implementing these storage mechanisms while the remaining parts could be handled using existing libraries? This is the role that GlueSQL aspires to play.

The Vision of GlueSQL

The GlueSQL project aims to offer a unified query interface for various environments. The goal is to allow anyone to port and use SQL and GlueSQL's proprietary query builder, the AST Builder, in any desired environment. This could range from key-value databases, serious NoSQL databases, log files, and even REST API services. Essentially, if a service supports reading or read-writing data, regardless of the data type, it can readily support a complex query interface via GlueSQL.

Presently, the GlueSQL project itself directly supports a few storage types as reference storages. These include in-memory storage for non-persistent data handling, sled storage, which is a key-value database written in Rust, JSON storage for handling JSON and JSONL files, and a storage that ports SQL to the web browser's IndexedDB. While the GlueSQL Team is primarily developing these, the aim is to allow anyone to create such custom storages for a wide array of purposes, thus enabling them to assemble the database of their choosing.

Imagine using GlueSQL's SQL and AST Builder everywhere, with the simple method of swapping out storages to operate in diverse settings. It could significantly reduce software development costs. Developers wouldn't need to learn the different usage methods for each database. Instead, they could focus solely on implementing business logic using the same interface.

Our vision is to reduce database development costs by 10 times, or even more than 20 times. We aim to gather diverse database creators under the GlueSQL banner, making it the go-to solution for cost-effective database development.

Benefits to Database Users: Unifying Query Interfaces, Streamlining Software Development, and Reducing Costs

From the perspective of the users who engage with databases, there has always been the burden of learning different interfaces to interact with each database. The approach required to work with Redis is different from that necessary for MongoDB. Likewise, handling SQL databases necessitates using SQL. Although SQL databases generally use a common SQL, the SQL they support can considerably vary when examined in detail.

Naturally, there are legitimate reasons for such differences. Each database focuses on different areas, and to cater to specialized functionalities, they incorporate dedicated interface mechanisms. However, not all application development needs to utilize these database-specific core special functionalities.

Let's look at a couple of examples:

Suppose you're developing a back-end application that uses MySQL as the database and Redis for caching. Due to the vast differences in handling SQL databases and Redis, you would have to develop using different methods when storing data.

Here's another scenario: +Imagine you're implementing a data migration pipeline between various databases and log files. Let's say you're transferring Parquet to Redis or MongoDB. In this case, you would need to convert data using different methods for each, all of which would be a cumbersome process.

In both of the above examples, GlueSQL can directly address and solve the issues. It offers the convenience of a uniform query interface to deal with these matters. In certain scenarios, even the construction of a data pipeline can potentially be solved with a single SQL query, thanks to GlueSQL.

Benefits to Database Developers: Drastically Lowering Development Costs and Simplifying the Creation of Purpose-Built Databases

If you want to support SQL in the desired environment, using GlueSQL essentially requires you to implement an interface for Storage. There's no need to support all functionalities from the beginning. You can start lightly, choosing and implementing storage features suitable for the environment you want to create. To facilitate this, GlueSQL also provides a library in the form of a test suite to easily validate the storage you've implemented.

Lowering development costs in this way will enable a broader range of developers to support the GlueSQL query interface. As more developers join, a significant synergy can be generated. Designing a query interface from scratch involves a great deal of work, including planning and supporting the interface for different target programming languages.

However, despite all this hard work, it is not easy to attract database users accustomed to different methods.

Consider that the SQL and AST Builder provided by GlueSQL are already securing numerous users. This eliminates the need for efforts to promote a newly planned query interface. Over the years, many new databases have emphasized compatibility with PostgreSQL or MySQL for similar reasons. As GlueSQL places a strong emphasis on portability in its query interface planning, it allows for more flexible configuration according to the desired situation. Through the AST Builder, it also eliminates the cost of porting to different languages.

For many database developers, using GlueSQL can be an optimal choice, as it can save costs and quickly secure users.

Let me mention one more thing: what's convenient for humans... could be applied to AI as well. Rather than making AI write automation code using different databases, providing a common query interface can be much more efficient.

The Future with GlueSQL

GlueSQL has been and will continue to improve and develop new features to enable portability in various environments. Thanks to the schemaless data support added last year, it is now possible to handle both structured data with schema and unstructured data like JSON simultaneously. This has significantly increased the range of storage environments that can be supported.

One of the key features added last year was the AST Builder. This feature allowed us to escape the confines of SQL and provide an interface for comfortably handling data in the programming languages used for development.

Of course, improving existing features is extremely important, and there are many new features to be added. As a major development plan this year, we aim to develop features to effectively attach GlueSQL to NoSQL databases with their own planners and execution layers. The GlueSQL query planner, currently at a basic level, will see significant changes this year. With the expansion of this planner, not only NoSQL databases but also other SQL databases could be supported without sacrificing performance using GlueSQL.

The synergy that arises from the combination of different databases is a significant bonus in this process.

The Journey of the GlueSQL Team

The GlueSQL project was first conceived in the fall of 2019, and since then we have been developing it continuously. Personally, I have created various products in a variety of environments, including game development, backend server, and frontend development over the past decade. The experience gained through this process was a major motivation to start the GlueSQL project.

To put it grandly, the inconveniences felt while using different databases in various environments were a major motivation, wouldn't you say?

The start was actually a bit simple. Around 2019, I was mainly doing web front-end development. However, the lack of a structured database for state management and internal data processing made it very uncomfortable, especially since I couldn't use SQL databases and the like. So I started to lightly create an SQL database that could run on a web browser. Also, I wanted to use Rust, but after failing to introduce it at the company I was working for at the time, I decided to use it in my own project.

But as I started developing, my dreams grew significantly. Beyond a SQL database that simply operates on a web browser, I started envisioning a database that fits the name "Glue", one that can easily be ported to various environments, and I continue that journey to this day.

Whether I took the database project too lightly, or because the features I wanted kept increasing, the content to be developed kept expanding. As a result, I ended up investing full time in the GlueSQL project development for over three years. For a year in between, I even juggled full-time software engineering work alongside GlueSQL development. Currently, I'm back to developing the GlueSQL project full time, alongside various part-time contributors.

Now, we're getting very close to the starting point of the picture I wanted to create through GlueSQL, and thankfully, with contributors joining me, I am not alone.

The Sustainability and Business Aspect of GlueSQL

I believe that what we create through GlueSQL will make a great contribution to the world and make many software engineers happy. This gives me immense strength to continue developing even in difficult situations. However, we cannot accomplish everything with pure passion alone. As much as the GlueSQL project can make a significant contribution, I also see it as holding great business value.

The business strategy of GlueSQL may be somewhat different from other databases. We distribute the project itself as open source under the Apache-2.0 license, so that anyone can use it fully, and we do not consider pricing methods such as restricting features to the storages we support. In fact, if there is any player who can do it better, there's no way to prevent them from taking the GlueSQL project and making it their own.

But we believe that GlueSQL has great potential in this regard. Anyone can participate and they are free to distribute their own storage in the way they want, whether it's open source, private, or commercial. This eliminates the need to create something to replace the GlueSQL project. We aim to prevent the need to recreate the wheel that we provide using GlueSQL.

Moreover, our GlueSQL team seeks to continually expand our group of developers and companies working with us. During this development process, while they can certainly implement everything on their own, there is also no reason not to collaborate with our GlueSQL Team, especially for databases like NoSQL that have their own planners and execution layers. If you have a REST API and want to enhance convenience through SQL support, you can do it yourself or you can collaborate with us.

In addition, for some storages, we can also participate as players in the same position as other custom storage developers. We plan to expand the GlueSQL ecosystem in various ways, such as technical support and storage development.

We are finally ready to provide GlueSQL to users at the production level. We are accelerating the development of GlueSQL. If you are a company interested in storage development like SQL support, or if you resonate with our vision and want to join us, please contact us at taehoon@gluesql.com.

Conclusion

The continued emergence of new databases is driven by the demand for diverse and specialized databases, such as those optimized for Large Language Models (LLMs) and databases catering to unique requirements, like embedded databases, OLAP, OLTP, and time-series data processing. However, developing a new database from scratch is a significant undertaking, requiring extensive work, which often results in high costs.

GlueSQL presents a solution to this challenge by providing a unified query interface that can be ported across various environments, from key-value databases, NoSQL databases, log files, to REST APIs. It allows anyone to create custom storages, reducing the need for developers to build entirely new databases and to learn different usage methods for each database. Instead, they can focus on implementing their business logic using the same interface.

From a user perspective, GlueSQL offers the convenience of a unified query interface, easing the burden of learning different interfaces for each database. This simplification of interface use can also extend to AI, potentially enhancing the efficiency of AI automation.

GlueSQL's development plan includes significant enhancements to its query planner and aims to enable effective attachment of GlueSQL to NoSQL databases. The synergy of combining different databases is a valuable bonus in this process.

Since its inception in the fall of 2019, the GlueSQL team has continuously developed the project, driven by the desire to mitigate the inconveniences encountered while using different databases in various environments. The journey has been a rewarding one, with the GlueSQL project now at a point where it closely resembles the envisioned product.

GlueSQL, distributed under the Apache-2.0 license, is free for anyone to use and adapt. While the GlueSQL team welcomes collaboration with other developers and companies, they also see significant potential for the project as a business venture. The team is working to expand the GlueSQL ecosystem through a variety of initiatives, including technical support and storage development.

With GlueSQL now sufficiently prepared for practical applications, the team invites companies interested in storage development or those who share their vision to join them in their journey of revolutionizing database development.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/blog/tags/index.html b/docs/0.16.0/blog/tags/index.html new file mode 100644 index 00000000..0575bcb0 --- /dev/null +++ b/docs/0.16.0/blog/tags/index.html @@ -0,0 +1,17 @@ + + + + + +Tags | GlueSQL + + + + + + + + + + \ No newline at end of file diff --git a/docs/0.16.0/blog/tags/nosql/index.html b/docs/0.16.0/blog/tags/nosql/index.html new file mode 100644 index 00000000..1d0230cc --- /dev/null +++ b/docs/0.16.0/blog/tags/nosql/index.html @@ -0,0 +1,29 @@ + + + + + +One post tagged with "nosql" | GlueSQL + + + + + +
+

One post tagged with "nosql"

View All Tags

· 11 min read
Taehoon Moon

Introduction

The divide between SQL and NoSQL databases has often presented challenges in database management. GlueSQL, a unique database maker library, aims to blur this boundary, providing a versatile tool for handling these two distinct types of databases.

In this article, we explore how GlueSQL navigates the features of SQL and NoSQL databases, offering an integrated solution that promotes flexibility and efficiency. With its ability to unify disparate database types, GlueSQL heralds a new age of adaptable database creation and management.

The Interface Perspective: SQL & AST Builder

When we talk about SQL databases, it's almost a given that they support SQL - the standard query language. Although there are slight variations between databases, the convenience of using a similar SQL language across multiple databases cannot be overstated. However, from a software engineer's perspective, there's room for improvement. In most software development scenarios, a specific programming language is used. SQL is a separate language, which can cause friction when integrating it into your software. As a result, rather than using raw SQL, many developers employ query builders or ORMs to manipulate SQL conveniently using their preferred programming language. Although it's not efficient to generate SQL using a query builder and then parse it again in the database, it's a practical and effective choice.

On the other hand, NoSQL databases offer different mechanisms. Some of them have their own language similar to SQL, but most provide an interface library developed specifically for each programming language. While SQL databases rely on external query builder libraries to provide an interface for each programming language, NoSQL databases mostly develop and offer these libraries themselves. If we discount the convenience of SQL language, this is one of the major factors that make NoSQL databases more comfortable to use. Since query builder libraries supporting SQL databases often cater to multiple SQL databases, they are limited in fully supporting unique features of each database. NoSQL databases, on the other hand, can freely manage their interface libraries without these restrictions.

Providing a query interface for each programming language is not a fundamental difference between SQL and NoSQL, but we generally accept it implicitly.

Let's see what happens if we break down this boundary, using GlueSQL as an example. As you can see from the SQL postfix, GlueSQL supports SQL and can be classified as an SQL database.

CREATE TABLE Glue (id INTEGER, name TEXT);

INSERT INTO Glue VALUES (1, "hello"), (2, "gluesql");

SELECT * FROM Glue WHERE id = 1;

However, GlueSQL also supports its own query builder, like a NoSQL database. +(Currently, only Rust is supported, but we're working on adding support for other languages.)

table("Glue")
.create_table()
.add_column("id INTEGER")
.add_column("name TEXT")
.execute(glue)

table("Glue")
.insert()
.values(vec![
vec![num(1), text("hello")],
vec![num(2), text("gluesql")],
])
.execute(glue)
.await;

table("Glue")
.select()
.filter(col("id").eq(1))
.execute(glue)
.await;

Let's reconsider the implicit distinction between SQL and NoSQL. GlueSQL indeed supports SQL, but it also officially develops and offers its own query builder. This query builder is not a secondary tool for SQL. While most SQL query builder libraries ultimately generate SQL strings, GlueSQL's builder directly creates an AST (Abstract Structure Tree) that is used for execution within GlueSQL. Hence, we call it the AST Builder. This means SQL and the AST Builder are two equally supported interfaces in GlueSQL.

This also offers an additional advantage:

table("Glue")
.select()
// 1.
.filter(col("id").eq(1))
// 2.
.filter("id = 1")
.execute(glue)
.await;

Because GlueSQL already supports SQL, not only can you use the custom interface in the AST Builder, but you can also use familiar SQL syntax in part. Whether you use col("id").eq(1) or "id = 1", you can use it in the way you prefer. The AST Builder interface, although initially unfamiliar, allows a gradual migration similar to writing SQL for your convenience.

Thus, we've dismantled one of the implicit distinctions between SQL and NoSQL. However, it's more of an implicit differentiation than a fundamental one. There are more significant design differences that we'll explore next.

Structured & Unstructured Data

In this section, we'll discuss how SQL and NoSQL handle data. SQL generally deals with structured data, and recently, it's been made to support semi-structured data as well. On the other hand, NoSQL supports schemaless, unstructured data. Then, we'll explain in detail how GlueSQL handles these two types of data. The last part of this section will provide a segue into the next section where we'll discuss the decomposition of database functions.

When talking about SQL databases, one aspect is usually considered together: SQL databases have a defined schema.

CREATE TABLE Foo (
id INTEGER,
name TEXT,
rate FLOAT NULL
);

However, these days, SQL databases tend to support semi-structured data types, such as LIST or JSON. But, supporting completely schemaless, unstructured data is a different matter. SQL databases typically require a minimum schema.

What about NoSQL databases? As NoSQL databases vary significantly, we can't make definitive statements. But let's consider a typical document database like MongoDB. Unlike SQL databases, it doesn't enforce a schema. Essentially, you can insert any form of data directly. Often, NoSQL databases support schemaless data, but they lack features that enforce a schema like SQL. They generally support structure via validation methods, rather than structured access.

Is there no choice but to distinguish between structured data and unstructured, schemaless data so clearly? GlueSQL is being developed with the goal of being adaptable in various environments. Being forced to choose regarding this schema constraint was quite inconvenient. We started pondering if we couldn't benefit from both aspects - supporting both schema and schemaless data simultaneously, and we eventually found the answer. Let's look at how GlueSQL currently solves this issue through familiar SQL examples.

CREATE TABLE Names (id INTEGER, name TEXT);
INSERT INTO Names VALUES (1, 'glue'), (2, 'sql');

You can create a regular table with a schema like this. But GlueSQL's choice for creating a schemaless table is as follows:

CREATE TABLE Logs;
INSERT INTO Logs VALUES
('{ "id": 1, "value": 30 }'),
('{ "id": 2, "rate": 3.0, "list": [1, 2, 3] }'),
('{ "id": 3, "rate": 5.0, "value": 100 }');

It creates a table without column definitions! If you do this, GlueSQL recognizes the table as schemaless and processes it internally.

SELECT id, rate, list[0] FROM Logs WHERE id = 2;

Although the way to create the table was a bit special, using it isn't much different from the regular SQL SELECT statement. Not only can you differentiate between schema and schemaless when creating tables, but you can also use them interchangeably!

SELECT * FROM Names JOIN Logs ON Names.id = Logs.id;
/*
| id | list | name | rate | value |
|----|---------|------|------|-------|
| 1 | | glue | | 30 |
| 2 |[1, 2, 3]| sql | 3 | |
*/

Here's an example of querying data by INNER JOINing the Names table, which has a schema, and the Logs table, which is schemaless. GlueSQL has resolved this problem by allowing the internal execution layer to handle both vector-type data, for cases where each row has a defined schema, and map-type data for schemaless cases.

Thanks to this, the variety of storage that can be supported through GlueSQL has expanded significantly. If there were previously limitations to supporting NoSQL databases that support schemaless data, that is no longer the case. The reference storage where you can directly experience this schemaless data support is JSON Storage. It offers features that allow you to deal directly with unstructured data like JSON using GlueSQL.

If GlueSQL starts from the perspective of an SQL database and expands, by providing the AST Builder directly, it once blurs the boundary, and by supporting unstructured data simultaneously, it knocks down the boundary once more. How do you like it?

Decomposing Database Functionality: Breaking Down SQL and NoSQL Features

The distinction between SQL and NoSQL is not just about whether they support unstructured data. Of course, there are examples like unstructured data, which is mainly supported only in NoSQL, but in many cases, SQL databases tend to support more diverse and complex queries. NoSQL often gains other advantages in exchange for reducing the range of query support provided by SQL databases.

GlueSQL is ambitious. It has devised a rather interesting method to support all of this through SQL and the AST Builder, with the same interface. When we usually say SQL database, it implicitly assumes that a lot of features have been fully implemented. Create tables by specifying a schema, modify schemas with "alter table", support both clustered and non-clustered indexes, and support transactions. And there's so much more. But the functionality that is naturally supported in SQL databases may not be natural in other environments.

Let's think about JSON Storage. GlueSQL's JSON Storage allows you to handle JSON, JSONL files using SQL and the AST Builder. This JSON Storage does not support atomic operations or transactions. Of course, it would be great if it did, but implementing and executing them would be a significant performance burden. In most cases, when you want to simply browse and handle JSONL files, the overhead caused by transactions can be an unnecessary burden. In this case, you want to handle JSON, JSONL files using SQL, but you don't necessarily need transactions.

To meet the requirements of these diverse environments, GlueSQL has separated the functionality of what we usually call an SQL database into multiple independent interfaces. +Store, StoreMut, AlterTable, Transaction, .. +These are just a few of the various storage interfaces that GlueSQL currently supports. +The way it works can be summarized like this: +If you implement Store, you can use SELECT. +And if you implement both Store and StoreMut, you can support quite a number of basic SQL statements including SELECT. +You can manage tables with CREATE TABLE, DROP TABLE, and handle data using INSERT, UPDATE, DELETE statements. +If you only need to retrieve data, you only need to implement Store. +If you want to support the ALTER TABLE statement, you can additionally implement the AlterTable interface. +The Transaction interface works the same way. +The interesting part is that, except for Store and StoreMut, all other storage interfaces can be implemented independently. GlueSQL allows you to choose and implement only the features you need. +And it's not just about providing interfaces. It also provides integration tests suitable for each situation to verify what you have implemented. You just need to implement the interface and import the corresponding test case for verification.

In addition to supporting both structured and unstructured data simultaneously, GlueSQL provides the ability to divide the functionality of a database into multiple independent features and selectively implement them. This allows GlueSQL to be ported to a wide variety of environments without any burden.

Conclusion

GlueSQL, while serving as a database that provides its own reference storage, is fundamentally a library designed to simplify the creation of databases. One of the substantial challenges GlueSQL had to overcome in order to support a diverse array of environments was to address the distinctive features that separate conventional SQL databases from NoSQL databases. GlueSQL achieved this through several innovative approaches, managing to support both categories simultaneously despite their significantly different characteristics.

It offers support for SQL alongside an AST Builder, and accommodates both structured and unstructured data. Additionally, it decomposes database functionalities into multiple independent features, allowing each environment to selectively implement the functionalities it requires.

These unique attributes enable GlueSQL to live up to its 'Glue' prefix by facilitating effortless porting across various environments. While we have been developing it for several years, there is still much ground to cover. However, the fact that we are now able to introduce it publicly attests to our successful technological validation and completion of a demonstrable level of implementation.

Through GlueSQL, we hope to provide developers with a unified query interface that can be customized according to their needs, thereby enabling them to produce efficient products more effortlessly. There's a promising future ahead for GlueSQL, and we look forward to its contributions to the technology community.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/blog/tags/proposal/index.html b/docs/0.16.0/blog/tags/proposal/index.html new file mode 100644 index 00000000..ee7a10d7 --- /dev/null +++ b/docs/0.16.0/blog/tags/proposal/index.html @@ -0,0 +1,18 @@ + + + + + +One post tagged with "proposal" | GlueSQL + + + + + +
+

One post tagged with "proposal"

View All Tags

· 14 min read
Taehoon Moon

Introduction

GlueSQL is a versatile database project designed for exceptional portability across a broad range of environments, from embedded systems and servers to web and mobile platforms. The core goal is to support diverse storage environments and manage various data types with a standard SQL approach.

Imagine handling files like CSV, JSONL, and Parquet, or transforming key-value or NoSQL databases such as RocksDB, Redis, and MongoDB into SQL-supporting databases—all feasible with GlueSQL. It can also operate with storages supported in web browsers.

GlueSQL's essential feature is providing a management layer for these diverse storage scenarios without requiring data migration. The broader aim is to facilitate portability of GlueSQL to any environment supporting read or read-write operations. This extends to APIs like GitHub, or messengers like Discord or Slack.

GlueSQL supports both structured and unstructured data and is written in Rust for compatibility with various environments. While portability is its core value, the emphasis is on creating an intuitive, comfortable development environment for easy custom storage implementation.

Ultimately, GlueSQL aims to significantly reduce the cost, time, and complexity of developing new databases. By leveraging GlueSQL for the parser, planner, and execution layer, developers can focus on creating specific storage implementations, leading to a more convenient query interface like SQL for many environments.

The Problem: Why Reinvent the Database?

Despite the numerous database implementations that currently exist, the emergence of new databases continues. The primary reason behind this trend is our need for databases for a broad spectrum of distinct purposes. For instance, new databases are surfacing that are specifically optimized for Large Language Models (LLMs) like ChatGPT. The range is wide and diverse, encompassing embedded databases, OLAP for data analysis, OLTP databases optimized for online transactions, databases specialized for time-series data processing, and many more.

With such varied requirements, we find ourselves in constant need of fresh databases. However, constructing a database from scratch is a monumental task. It necessitates defining a query interface for handling the database and implementing a corresponding parser. Moreover, a separate execution layer for running operations must be built. Also, the planning layer, which is responsible for devising execution strategies, is a vital aspect of this process. Let's not forget about the critical storage layer that physically reads and stores the data. In a nutshell, there's a daunting amount of work involved in developing a new database.

Given these circumstances, it's understandable why numerous emerging databases resort to high pricing structures—they need immediate revenue to offset continuous development costs.

But the story doesn't end here. Query interfaces like SQL are indeed useful for serious tasks, but they also provide excellent utility for handling simple log files such as CSV, JSONL, Parquet, and even for utilizing REST APIs for various applications. The issue arises when a complex query interface needs to be provided even for these lighter storage requirements—it necessitates a development process almost identical to building a sophisticated database. Implementing an entire parser and execution layer just to add SQL support to an existing service can seem like an excessive burden.

Whether it's a simple storage environment or a serious task, the key lies in the storage layer, which involves the actual reading and storing of data. So, what if developers focused on implementing these storage mechanisms while the remaining parts could be handled using existing libraries? This is the role that GlueSQL aspires to play.

The Vision of GlueSQL

The GlueSQL project aims to offer a unified query interface for various environments. The goal is to allow anyone to port and use SQL and GlueSQL's proprietary query builder, the AST Builder, in any desired environment. This could range from key-value databases, serious NoSQL databases, log files, and even REST API services. Essentially, if a service supports reading or read-writing data, regardless of the data type, it can readily support a complex query interface via GlueSQL.

Presently, the GlueSQL project itself directly supports a few storage types as reference storages. These include in-memory storage for non-persistent data handling, sled storage, which is a key-value database written in Rust, JSON storage for handling JSON and JSONL files, and a storage that ports SQL to the web browser's IndexedDB. While the GlueSQL Team is primarily developing these, the aim is to allow anyone to create such custom storages for a wide array of purposes, thus enabling them to assemble the database of their choosing.

Imagine using GlueSQL's SQL and AST Builder everywhere, with the simple method of swapping out storages to operate in diverse settings. It could significantly reduce software development costs. Developers wouldn't need to learn the different usage methods for each database. Instead, they could focus solely on implementing business logic using the same interface.

Our vision is to reduce database development costs by 10 times, or even more than 20 times. We aim to gather diverse database creators under the GlueSQL banner, making it the go-to solution for cost-effective database development.

Benefits to Database Users: Unifying Query Interfaces, Streamlining Software Development, and Reducing Costs

From the perspective of the users who engage with databases, there has always been the burden of learning different interfaces to interact with each database. The approach required to work with Redis is different from that necessary for MongoDB. Likewise, handling SQL databases necessitates using SQL. Although SQL databases generally use a common SQL, the SQL they support can considerably vary when examined in detail.

Naturally, there are legitimate reasons for such differences. Each database focuses on different areas, and to cater to specialized functionalities, they incorporate dedicated interface mechanisms. However, not all application development needs to utilize these database-specific core special functionalities.

Let's look at a couple of examples:

Suppose you're developing a back-end application that uses MySQL as the database and Redis for caching. Due to the vast differences in handling SQL databases and Redis, you would have to develop using different methods when storing data.

Here's another scenario: +Imagine you're implementing a data migration pipeline between various databases and log files. Let's say you're transferring Parquet to Redis or MongoDB. In this case, you would need to convert data using different methods for each, all of which would be a cumbersome process.

In both of the above examples, GlueSQL can directly address and solve the issues. It offers the convenience of a uniform query interface to deal with these matters. In certain scenarios, even the construction of a data pipeline can potentially be solved with a single SQL query, thanks to GlueSQL.

Benefits to Database Developers: Drastically Lowering Development Costs and Simplifying the Creation of Purpose-Built Databases

If you want to support SQL in the desired environment, using GlueSQL essentially requires you to implement an interface for Storage. There's no need to support all functionalities from the beginning. You can start lightly, choosing and implementing storage features suitable for the environment you want to create. To facilitate this, GlueSQL also provides a library in the form of a test suite to easily validate the storage you've implemented.

Lowering development costs in this way will enable a broader range of developers to support the GlueSQL query interface. As more developers join, a significant synergy can be generated. Designing a query interface from scratch involves a great deal of work, including planning and supporting the interface for different target programming languages.

However, despite all this hard work, it is not easy to attract database users accustomed to different methods.

Consider that the SQL and AST Builder provided by GlueSQL are already securing numerous users. This eliminates the need for efforts to promote a newly planned query interface. Over the years, many new databases have emphasized compatibility with PostgreSQL or MySQL for similar reasons. As GlueSQL places a strong emphasis on portability in its query interface planning, it allows for more flexible configuration according to the desired situation. Through the AST Builder, it also eliminates the cost of porting to different languages.

For many database developers, using GlueSQL can be an optimal choice, as it can save costs and quickly secure users.

Let me mention one more thing: what's convenient for humans... could be applied to AI as well. Rather than making AI write automation code using different databases, providing a common query interface can be much more efficient.

The Future with GlueSQL

GlueSQL has been and will continue to improve and develop new features to enable portability in various environments. Thanks to the schemaless data support added last year, it is now possible to handle both structured data with schema and unstructured data like JSON simultaneously. This has significantly increased the range of storage environments that can be supported.

One of the key features added last year was the AST Builder. This feature allowed us to escape the confines of SQL and provide an interface for comfortably handling data in the programming languages used for development.

Of course, improving existing features is extremely important, and there are many new features to be added. As a major development plan this year, we aim to develop features to effectively attach GlueSQL to NoSQL databases with their own planners and execution layers. The GlueSQL query planner, currently at a basic level, will see significant changes this year. With the expansion of this planner, not only NoSQL databases but also other SQL databases could be supported without sacrificing performance using GlueSQL.

The synergy that arises from the combination of different databases is a significant bonus in this process.

The Journey of the GlueSQL Team

The GlueSQL project was first conceived in the fall of 2019, and since then we have been developing it continuously. Personally, I have created various products in a variety of environments, including game development, backend server, and frontend development over the past decade. The experience gained through this process was a major motivation to start the GlueSQL project.

To put it grandly, the inconveniences felt while using different databases in various environments were a major motivation, wouldn't you say?

The start was actually a bit simple. Around 2019, I was mainly doing web front-end development. However, the lack of a structured database for state management and internal data processing made it very uncomfortable, especially since I couldn't use SQL databases and the like. So I started to lightly create an SQL database that could run on a web browser. Also, I wanted to use Rust, but after failing to introduce it at the company I was working for at the time, I decided to use it in my own project.

But as I started developing, my dreams grew significantly. Beyond a SQL database that simply operates on a web browser, I started envisioning a database that fits the name "Glue", one that can easily be ported to various environments, and I continue that journey to this day.

Whether I took the database project too lightly, or because the features I wanted kept increasing, the content to be developed kept expanding. As a result, I ended up investing full time in the GlueSQL project development for over three years. For a year in between, I even juggled full-time software engineering work alongside GlueSQL development. Currently, I'm back to developing the GlueSQL project full time, alongside various part-time contributors.

Now, we're getting very close to the starting point of the picture I wanted to create through GlueSQL, and thankfully, with contributors joining me, I am not alone.

The Sustainability and Business Aspect of GlueSQL

I believe that what we create through GlueSQL will make a great contribution to the world and make many software engineers happy. This gives me immense strength to continue developing even in difficult situations. However, we cannot accomplish everything with pure passion alone. As much as the GlueSQL project can make a significant contribution, I also see it as holding great business value.

The business strategy of GlueSQL may be somewhat different from other databases. We distribute the project itself as open source under the Apache-2.0 license, so that anyone can use it fully, and we do not consider pricing methods such as restricting features to the storages we support. In fact, if there is any player who can do it better, there's no way to prevent them from taking the GlueSQL project and making it their own.

But we believe that GlueSQL has great potential in this regard. Anyone can participate and they are free to distribute their own storage in the way they want, whether it's open source, private, or commercial. This eliminates the need to create something to replace the GlueSQL project. We aim to prevent the need to recreate the wheel that we provide using GlueSQL.

Moreover, our GlueSQL team seeks to continually expand our group of developers and companies working with us. During this development process, while they can certainly implement everything on their own, there is also no reason not to collaborate with our GlueSQL Team, especially for databases like NoSQL that have their own planners and execution layers. If you have a REST API and want to enhance convenience through SQL support, you can do it yourself or you can collaborate with us.

In addition, for some storages, we can also participate as players in the same position as other custom storage developers. We plan to expand the GlueSQL ecosystem in various ways, such as technical support and storage development.

We are finally ready to provide GlueSQL to users at the production level. We are accelerating the development of GlueSQL. If you are a company interested in storage development like SQL support, or if you resonate with our vision and want to join us, please contact us at taehoon@gluesql.com.

Conclusion

The continued emergence of new databases is driven by the demand for diverse and specialized databases, such as those optimized for Large Language Models (LLMs) and databases catering to unique requirements, like embedded databases, OLAP, OLTP, and time-series data processing. However, developing a new database from scratch is a significant undertaking, requiring extensive work, which often results in high costs.

GlueSQL presents a solution to this challenge by providing a unified query interface that can be ported across various environments, from key-value databases, NoSQL databases, log files, to REST APIs. It allows anyone to create custom storages, reducing the need for developers to build entirely new databases and to learn different usage methods for each database. Instead, they can focus on implementing their business logic using the same interface.

From a user perspective, GlueSQL offers the convenience of a unified query interface, easing the burden of learning different interfaces for each database. This simplification of interface use can also extend to AI, potentially enhancing the efficiency of AI automation.

GlueSQL's development plan includes significant enhancements to its query planner and aims to enable effective attachment of GlueSQL to NoSQL databases. The synergy of combining different databases is a valuable bonus in this process.

Since its inception in the fall of 2019, the GlueSQL team has continuously developed the project, driven by the desire to mitigate the inconveniences encountered while using different databases in various environments. The journey has been a rewarding one, with the GlueSQL project now at a point where it closely resembles the envisioned product.

GlueSQL, distributed under the Apache-2.0 license, is free for anyone to use and adapt. While the GlueSQL team welcomes collaboration with other developers and companies, they also see significant potential for the project as a business venture. The team is working to expand the GlueSQL ecosystem through a variety of initiatives, including technical support and storage development.

With GlueSQL now sufficiently prepared for practical applications, the team invites companies interested in storage development or those who share their vision to join them in their journey of revolutionizing database development.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/blog/tags/query-interface/index.html b/docs/0.16.0/blog/tags/query-interface/index.html new file mode 100644 index 00000000..23a942ae --- /dev/null +++ b/docs/0.16.0/blog/tags/query-interface/index.html @@ -0,0 +1,18 @@ + + + + + +One post tagged with "query-interface" | GlueSQL + + + + + +
+

One post tagged with "query-interface"

View All Tags

· 14 min read
Taehoon Moon

Introduction

GlueSQL is a versatile database project designed for exceptional portability across a broad range of environments, from embedded systems and servers to web and mobile platforms. The core goal is to support diverse storage environments and manage various data types with a standard SQL approach.

Imagine handling files like CSV, JSONL, and Parquet, or transforming key-value or NoSQL databases such as RocksDB, Redis, and MongoDB into SQL-supporting databases—all feasible with GlueSQL. It can also operate with storages supported in web browsers.

GlueSQL's essential feature is providing a management layer for these diverse storage scenarios without requiring data migration. The broader aim is to facilitate portability of GlueSQL to any environment supporting read or read-write operations. This extends to APIs like GitHub, or messengers like Discord or Slack.

GlueSQL supports both structured and unstructured data and is written in Rust for compatibility with various environments. While portability is its core value, the emphasis is on creating an intuitive, comfortable development environment for easy custom storage implementation.

Ultimately, GlueSQL aims to significantly reduce the cost, time, and complexity of developing new databases. By leveraging GlueSQL for the parser, planner, and execution layer, developers can focus on creating specific storage implementations, leading to a more convenient query interface like SQL for many environments.

The Problem: Why Reinvent the Database?

Despite the numerous database implementations that currently exist, the emergence of new databases continues. The primary reason behind this trend is our need for databases for a broad spectrum of distinct purposes. For instance, new databases are surfacing that are specifically optimized for Large Language Models (LLMs) like ChatGPT. The range is wide and diverse, encompassing embedded databases, OLAP for data analysis, OLTP databases optimized for online transactions, databases specialized for time-series data processing, and many more.

With such varied requirements, we find ourselves in constant need of fresh databases. However, constructing a database from scratch is a monumental task. It necessitates defining a query interface for handling the database and implementing a corresponding parser. Moreover, a separate execution layer for running operations must be built. Also, the planning layer, which is responsible for devising execution strategies, is a vital aspect of this process. Let's not forget about the critical storage layer that physically reads and stores the data. In a nutshell, there's a daunting amount of work involved in developing a new database.

Given these circumstances, it's understandable why numerous emerging databases resort to high pricing structures—they need immediate revenue to offset continuous development costs.

But the story doesn't end here. Query interfaces like SQL are indeed useful for serious tasks, but they also provide excellent utility for handling simple log files such as CSV, JSONL, Parquet, and even for utilizing REST APIs for various applications. The issue arises when a complex query interface needs to be provided even for these lighter storage requirements—it necessitates a development process almost identical to building a sophisticated database. Implementing an entire parser and execution layer just to add SQL support to an existing service can seem like an excessive burden.

Whether it's a simple storage environment or a serious task, the key lies in the storage layer, which involves the actual reading and storing of data. So, what if developers focused on implementing these storage mechanisms while the remaining parts could be handled using existing libraries? This is the role that GlueSQL aspires to play.

The Vision of GlueSQL

The GlueSQL project aims to offer a unified query interface for various environments. The goal is to allow anyone to port and use SQL and GlueSQL's proprietary query builder, the AST Builder, in any desired environment. This could range from key-value databases, serious NoSQL databases, log files, and even REST API services. Essentially, if a service supports reading or read-writing data, regardless of the data type, it can readily support a complex query interface via GlueSQL.

Presently, the GlueSQL project itself directly supports a few storage types as reference storages. These include in-memory storage for non-persistent data handling, sled storage, which is a key-value database written in Rust, JSON storage for handling JSON and JSONL files, and a storage that ports SQL to the web browser's IndexedDB. While the GlueSQL Team is primarily developing these, the aim is to allow anyone to create such custom storages for a wide array of purposes, thus enabling them to assemble the database of their choosing.

Imagine using GlueSQL's SQL and AST Builder everywhere, with the simple method of swapping out storages to operate in diverse settings. It could significantly reduce software development costs. Developers wouldn't need to learn the different usage methods for each database. Instead, they could focus solely on implementing business logic using the same interface.

Our vision is to reduce database development costs by 10 times, or even more than 20 times. We aim to gather diverse database creators under the GlueSQL banner, making it the go-to solution for cost-effective database development.

Benefits to Database Users: Unifying Query Interfaces, Streamlining Software Development, and Reducing Costs

From the perspective of the users who engage with databases, there has always been the burden of learning different interfaces to interact with each database. The approach required to work with Redis is different from that necessary for MongoDB. Likewise, handling SQL databases necessitates using SQL. Although SQL databases generally use a common SQL, the SQL they support can considerably vary when examined in detail.

Naturally, there are legitimate reasons for such differences. Each database focuses on different areas, and to cater to specialized functionalities, they incorporate dedicated interface mechanisms. However, not all application development needs to utilize these database-specific core special functionalities.

Let's look at a couple of examples:

Suppose you're developing a back-end application that uses MySQL as the database and Redis for caching. Due to the vast differences in handling SQL databases and Redis, you would have to develop using different methods when storing data.

Here's another scenario: +Imagine you're implementing a data migration pipeline between various databases and log files. Let's say you're transferring Parquet to Redis or MongoDB. In this case, you would need to convert data using different methods for each, all of which would be a cumbersome process.

In both of the above examples, GlueSQL can directly address and solve the issues. It offers the convenience of a uniform query interface to deal with these matters. In certain scenarios, even the construction of a data pipeline can potentially be solved with a single SQL query, thanks to GlueSQL.

Benefits to Database Developers: Drastically Lowering Development Costs and Simplifying the Creation of Purpose-Built Databases

If you want to support SQL in the desired environment, using GlueSQL essentially requires you to implement an interface for Storage. There's no need to support all functionalities from the beginning. You can start lightly, choosing and implementing storage features suitable for the environment you want to create. To facilitate this, GlueSQL also provides a library in the form of a test suite to easily validate the storage you've implemented.

Lowering development costs in this way will enable a broader range of developers to support the GlueSQL query interface. As more developers join, a significant synergy can be generated. Designing a query interface from scratch involves a great deal of work, including planning and supporting the interface for different target programming languages.

However, despite all this hard work, it is not easy to attract database users accustomed to different methods.

Consider that the SQL and AST Builder provided by GlueSQL are already securing numerous users. This eliminates the need for efforts to promote a newly planned query interface. Over the years, many new databases have emphasized compatibility with PostgreSQL or MySQL for similar reasons. As GlueSQL places a strong emphasis on portability in its query interface planning, it allows for more flexible configuration according to the desired situation. Through the AST Builder, it also eliminates the cost of porting to different languages.

For many database developers, using GlueSQL can be an optimal choice, as it can save costs and quickly secure users.

Let me mention one more thing: what's convenient for humans... could be applied to AI as well. Rather than making AI write automation code using different databases, providing a common query interface can be much more efficient.

The Future with GlueSQL

GlueSQL has been and will continue to improve and develop new features to enable portability in various environments. Thanks to the schemaless data support added last year, it is now possible to handle both structured data with schema and unstructured data like JSON simultaneously. This has significantly increased the range of storage environments that can be supported.

One of the key features added last year was the AST Builder. This feature allowed us to escape the confines of SQL and provide an interface for comfortably handling data in the programming languages used for development.

Of course, improving existing features is extremely important, and there are many new features to be added. As a major development plan this year, we aim to develop features to effectively attach GlueSQL to NoSQL databases with their own planners and execution layers. The GlueSQL query planner, currently at a basic level, will see significant changes this year. With the expansion of this planner, not only NoSQL databases but also other SQL databases could be supported without sacrificing performance using GlueSQL.

The synergy that arises from the combination of different databases is a significant bonus in this process.

The Journey of the GlueSQL Team

The GlueSQL project was first conceived in the fall of 2019, and since then we have been developing it continuously. Personally, I have created various products in a variety of environments, including game development, backend server, and frontend development over the past decade. The experience gained through this process was a major motivation to start the GlueSQL project.

To put it grandly, the inconveniences felt while using different databases in various environments were a major motivation, wouldn't you say?

The start was actually a bit simple. Around 2019, I was mainly doing web front-end development. However, the lack of a structured database for state management and internal data processing made it very uncomfortable, especially since I couldn't use SQL databases and the like. So I started to lightly create an SQL database that could run on a web browser. Also, I wanted to use Rust, but after failing to introduce it at the company I was working for at the time, I decided to use it in my own project.

But as I started developing, my dreams grew significantly. Beyond a SQL database that simply operates on a web browser, I started envisioning a database that fits the name "Glue", one that can easily be ported to various environments, and I continue that journey to this day.

Whether I took the database project too lightly, or because the features I wanted kept increasing, the content to be developed kept expanding. As a result, I ended up investing full time in the GlueSQL project development for over three years. For a year in between, I even juggled full-time software engineering work alongside GlueSQL development. Currently, I'm back to developing the GlueSQL project full time, alongside various part-time contributors.

Now, we're getting very close to the starting point of the picture I wanted to create through GlueSQL, and thankfully, with contributors joining me, I am not alone.

The Sustainability and Business Aspect of GlueSQL

I believe that what we create through GlueSQL will make a great contribution to the world and make many software engineers happy. This gives me immense strength to continue developing even in difficult situations. However, we cannot accomplish everything with pure passion alone. As much as the GlueSQL project can make a significant contribution, I also see it as holding great business value.

The business strategy of GlueSQL may be somewhat different from other databases. We distribute the project itself as open source under the Apache-2.0 license, so that anyone can use it fully, and we do not consider pricing methods such as restricting features to the storages we support. In fact, if there is any player who can do it better, there's no way to prevent them from taking the GlueSQL project and making it their own.

But we believe that GlueSQL has great potential in this regard. Anyone can participate and they are free to distribute their own storage in the way they want, whether it's open source, private, or commercial. This eliminates the need to create something to replace the GlueSQL project. We aim to prevent the need to recreate the wheel that we provide using GlueSQL.

Moreover, our GlueSQL team seeks to continually expand our group of developers and companies working with us. During this development process, while they can certainly implement everything on their own, there is also no reason not to collaborate with our GlueSQL Team, especially for databases like NoSQL that have their own planners and execution layers. If you have a REST API and want to enhance convenience through SQL support, you can do it yourself or you can collaborate with us.

In addition, for some storages, we can also participate as players in the same position as other custom storage developers. We plan to expand the GlueSQL ecosystem in various ways, such as technical support and storage development.

We are finally ready to provide GlueSQL to users at the production level. We are accelerating the development of GlueSQL. If you are a company interested in storage development like SQL support, or if you resonate with our vision and want to join us, please contact us at taehoon@gluesql.com.

Conclusion

The continued emergence of new databases is driven by the demand for diverse and specialized databases, such as those optimized for Large Language Models (LLMs) and databases catering to unique requirements, like embedded databases, OLAP, OLTP, and time-series data processing. However, developing a new database from scratch is a significant undertaking, requiring extensive work, which often results in high costs.

GlueSQL presents a solution to this challenge by providing a unified query interface that can be ported across various environments, from key-value databases, NoSQL databases, log files, to REST APIs. It allows anyone to create custom storages, reducing the need for developers to build entirely new databases and to learn different usage methods for each database. Instead, they can focus on implementing their business logic using the same interface.

From a user perspective, GlueSQL offers the convenience of a unified query interface, easing the burden of learning different interfaces for each database. This simplification of interface use can also extend to AI, potentially enhancing the efficiency of AI automation.

GlueSQL's development plan includes significant enhancements to its query planner and aims to enable effective attachment of GlueSQL to NoSQL databases. The synergy of combining different databases is a valuable bonus in this process.

Since its inception in the fall of 2019, the GlueSQL team has continuously developed the project, driven by the desire to mitigate the inconveniences encountered while using different databases in various environments. The journey has been a rewarding one, with the GlueSQL project now at a point where it closely resembles the envisioned product.

GlueSQL, distributed under the Apache-2.0 license, is free for anyone to use and adapt. While the GlueSQL team welcomes collaboration with other developers and companies, they also see significant potential for the project as a business venture. The team is working to expand the GlueSQL ecosystem through a variety of initiatives, including technical support and storage development.

With GlueSQL now sufficiently prepared for practical applications, the team invites companies interested in storage development or those who share their vision to join them in their journey of revolutionizing database development.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/blog/tags/release-note/index.html b/docs/0.16.0/blog/tags/release-note/index.html new file mode 100644 index 00000000..19f6899a --- /dev/null +++ b/docs/0.16.0/blog/tags/release-note/index.html @@ -0,0 +1,19 @@ + + + + + +2 posts tagged with "release-note" | GlueSQL + + + + + +
+

2 posts tagged with "release-note"

View All Tags

· 6 min read
Taehoon Moon

🌊 Breaking Changes

🍀 Python Support

Code Samples

from gluesql import Glue, MemoryStorage
from tabulate import tabulate

db = Glue(MemoryStorage())

sql = """
SELECT
u.name as user,
d.name as device
FROM User u
JOIN Device d ON u.id = d.userId
""".strip().replace(
" ", ""
)

result = db.query(sql)
rows = result[0].get("rows")
print(f"\n[Query]\n{sql}")
print(tabulate(rows, headers="keys", showindex=True, tablefmt="simple_outline"))

🍀 Redis Storage

🍀 CSV Storage

🍀 More operators and functions

🚀 Features

  • feat: implement select iterator utility function @ever0de (#1429)

🌟 Improvements

🐛 Bug Fixes

  • fix: Literal comparison with BinaryOperator @ding-co (#1397)
  • fix: update Key.cmp to compare a type with other type @tgsong827 (#1367)
  • Fix Value::evaluate_cmp_with_literal between Decimal and Literal::Num… @panarch (#1352)
  • Fix spool on tabular off and SelectMap @devgony (#1314)
  • Update auto-assign-action to be triggered on PR open from fork repos @panarch (#1313)
  • Fix Scala Subquery should contain only 1 column @ChobobDev (#1284)
  • Wrap config path by quotes in auto-author-assign.yml @panarch (#1258)
  • Apply word-wrap to docs/ article h1 @panarch (#1230)
  • Fix docusaurus.config.js themeConfig handler @panarch (#1225)

👏 New Contributors

Full Changelog: https://github.com/gluesql/gluesql/compare/v0.14.0...v0.15.0

· 11 min read
Taehoon Moon

We now provide an official documentation website at https://gluesql.org/docs

🚀 Features

🍀 Schemaless data support

GlueSQL now supports creating tables without a schema, allowing for both structured and unstructured data to be stored in the same table. +To create a schemaless table, simply run CREATE TABLE without specifying any columns. For more information on querying schemaless data, please refer to the following link: querying schemaless data

CREATE TABLE Bar;

To insert values,

INSERT INTO Bar VALUES
('{ "name": "ast", "value": 30 }'),
('{ "name": "glue", "rate": 3.0, "list": [1, 2, 3] }'),

Then, selecting values from schemaless table is simple.

SELECT name, rate, list[0] FROM Bar WHERE name = 'glue';

e.g.

CREATE TABLE Names (id INTEGER, name TEXT);
INSERT INTO Names VALUES (1, 'glue'), (2, 'sql');

CREATE TABLE Logs;
INSERT INTO Logs VALUES
('{ "id": 1, "value": 30 }'),
('{ "id": 2, "rate": 3.0, "list": [1, 2, 3] }'),
('{ "id": 3, "rate": 5.0, "value": 100 }');

SELECT * FROM Names JOIN Logs ON Names.id = Logs.id;
/*
| id | list | name | rate | value |
|----|---------|------|------|-------|
| 1 | | glue | | 30 |
| 2 |[1, 2, 3]| sql | 3 | |
*/

🍀 IndexedDB & WebStorage supports in JavaScript package

GlueSQL supports handling in-memory, localStorage, sessionStorage, and even IndexedDB using the same SQL syntax. All you need to know is how to specify the ENGINE when creating a table.

e.g.

CREATE TABLE Mem (mid INTEGER) ENGINE = memory;
CREATE TABLE Loc (lid INTEGER) ENGINE = localStorage;
CREATE TABLE Ses (sid INTEGER) ENGINE = sessionStorage;
CREATE TABLE Idb (iid INTEGER) ENGINE = indexedDB;

SELECT
mid, lid, sid, iid
FROM Mem
JOIN Loc
JOIN Ses
JOIN Idb;

🍀 Data Types - UINT32, UINT64, UINT128, POINT and FLOAT32

🍀 Functions - APPEND, PREPEND, RAND, FIND_IDX, INITCAP and CALC_DISTANCE

🍀 Store traits

User-level custom function

By implementing both the CustomFunction and CustomFunctionMut traits, users can create, use, and delete user-level custom functions. Although GlueSQL plans to continuously add various functions, users may still find them insufficient. In such cases, users can create their own user-level custom functions to supplement the built-in functions. Additionally, if there are repetitive business logic codes, they can be stored as custom functions. +e.g.

CREATE FUNCTION ADD_ONE (n INT, x INT DEFAULT 1) RETURN n + x;

SELECT ADD_ONE(10) AS test;

DROP FUNCTION ADD_ONE;

Metadata

The Metadata trait is an optional implementation for providing additional metadata support in GlueSQL. GlueSQL does not enforce any specific metadata implementation, allowing custom storage developers to decide which type of metadata, such as create time, modify time, etc., they want to provide.

🍀 Storages

JSON Storage

Composite Storage

  • Add CompositeStorage which bundles multiple storages @panarch (#1068)

IndexedDB Storage

Web Storage

  • Add WebStorage - support localStorage \& sessionStorage for web browsers @panarch (#1050)

🍀 Other new features

🌊 Interface Changes

  • Remove Store trait related cfg features, @panarch (#1091)
  • Refactor CreateTable.columns from Vec<ColumnDef> to Option<Vec<ColumnDef>> @devgony (#1086)
  • Remove MutResult @panarch (#1073)
  • Update all store mut trait methods to take \&mut self @panarch (#1072)
  • Change StoreMut interface to use \&mut self, not to take ownership @panarch (#1071)
  • Modify default ColumnOption from NOT NULL to NULL @devgony (#997)

🌟 Improvements

🌳 Documentation

We now provide an official documentation website at https://gluesql.org/docs

Docs - setup

📋 Tests

🐛 Bug Fixes

  • Fix docusaurus pages/index broken link @panarch (#1214)
  • Fix docs/ Discord GlueSQL channel invite link address @panarch (#1213)
  • Fix InvalidJsonString error message replacing payload to fileName @devgony (#1185)
  • Fix TryFrom Value::Str to u128 not to use parse_uuid @ChobobDev (#1134)
  • Fix column alias with identifer for TableFactor::Derived @ding-young (#1119)
  • Pass data even when deleted_by is not present @ever0de (#1117)
  • Fix MemoryStorage \& WebStorage primary key support @panarch (#1115)
  • Fix plan::validate to handle CTAS and ITAS adding unit test @devgony (#1074)
  • Fix test-suite tester functions to show (found, expected) shape @panarch (#1028)
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/blog/tags/sql/index.html b/docs/0.16.0/blog/tags/sql/index.html new file mode 100644 index 00000000..c8e642f4 --- /dev/null +++ b/docs/0.16.0/blog/tags/sql/index.html @@ -0,0 +1,29 @@ + + + + + +One post tagged with "sql" | GlueSQL + + + + + +
+

One post tagged with "sql"

View All Tags

· 11 min read
Taehoon Moon

Introduction

The divide between SQL and NoSQL databases has often presented challenges in database management. GlueSQL, a unique database maker library, aims to blur this boundary, providing a versatile tool for handling these two distinct types of databases.

In this article, we explore how GlueSQL navigates the features of SQL and NoSQL databases, offering an integrated solution that promotes flexibility and efficiency. With its ability to unify disparate database types, GlueSQL heralds a new age of adaptable database creation and management.

The Interface Perspective: SQL & AST Builder

When we talk about SQL databases, it's almost a given that they support SQL - the standard query language. Although there are slight variations between databases, the convenience of using a similar SQL language across multiple databases cannot be overstated. However, from a software engineer's perspective, there's room for improvement. In most software development scenarios, a specific programming language is used. SQL is a separate language, which can cause friction when integrating it into your software. As a result, rather than using raw SQL, many developers employ query builders or ORMs to manipulate SQL conveniently using their preferred programming language. Although it's not efficient to generate SQL using a query builder and then parse it again in the database, it's a practical and effective choice.

On the other hand, NoSQL databases offer different mechanisms. Some of them have their own language similar to SQL, but most provide an interface library developed specifically for each programming language. While SQL databases rely on external query builder libraries to provide an interface for each programming language, NoSQL databases mostly develop and offer these libraries themselves. If we discount the convenience of SQL language, this is one of the major factors that make NoSQL databases more comfortable to use. Since query builder libraries supporting SQL databases often cater to multiple SQL databases, they are limited in fully supporting unique features of each database. NoSQL databases, on the other hand, can freely manage their interface libraries without these restrictions.

Providing a query interface for each programming language is not a fundamental difference between SQL and NoSQL, but we generally accept it implicitly.

Let's see what happens if we break down this boundary, using GlueSQL as an example. As you can see from the SQL postfix, GlueSQL supports SQL and can be classified as an SQL database.

CREATE TABLE Glue (id INTEGER, name TEXT);

INSERT INTO Glue VALUES (1, "hello"), (2, "gluesql");

SELECT * FROM Glue WHERE id = 1;

However, GlueSQL also supports its own query builder, like a NoSQL database. +(Currently, only Rust is supported, but we're working on adding support for other languages.)

table("Glue")
.create_table()
.add_column("id INTEGER")
.add_column("name TEXT")
.execute(glue)

table("Glue")
.insert()
.values(vec![
vec![num(1), text("hello")],
vec![num(2), text("gluesql")],
])
.execute(glue)
.await;

table("Glue")
.select()
.filter(col("id").eq(1))
.execute(glue)
.await;

Let's reconsider the implicit distinction between SQL and NoSQL. GlueSQL indeed supports SQL, but it also officially develops and offers its own query builder. This query builder is not a secondary tool for SQL. While most SQL query builder libraries ultimately generate SQL strings, GlueSQL's builder directly creates an AST (Abstract Structure Tree) that is used for execution within GlueSQL. Hence, we call it the AST Builder. This means SQL and the AST Builder are two equally supported interfaces in GlueSQL.

This also offers an additional advantage:

table("Glue")
.select()
// 1.
.filter(col("id").eq(1))
// 2.
.filter("id = 1")
.execute(glue)
.await;

Because GlueSQL already supports SQL, not only can you use the custom interface in the AST Builder, but you can also use familiar SQL syntax in part. Whether you use col("id").eq(1) or "id = 1", you can use it in the way you prefer. The AST Builder interface, although initially unfamiliar, allows a gradual migration similar to writing SQL for your convenience.

Thus, we've dismantled one of the implicit distinctions between SQL and NoSQL. However, it's more of an implicit differentiation than a fundamental one. There are more significant design differences that we'll explore next.

Structured & Unstructured Data

In this section, we'll discuss how SQL and NoSQL handle data. SQL generally deals with structured data, and recently, it's been made to support semi-structured data as well. On the other hand, NoSQL supports schemaless, unstructured data. Then, we'll explain in detail how GlueSQL handles these two types of data. The last part of this section will provide a segue into the next section where we'll discuss the decomposition of database functions.

When talking about SQL databases, one aspect is usually considered together: SQL databases have a defined schema.

CREATE TABLE Foo (
id INTEGER,
name TEXT,
rate FLOAT NULL
);

However, these days, SQL databases tend to support semi-structured data types, such as LIST or JSON. But, supporting completely schemaless, unstructured data is a different matter. SQL databases typically require a minimum schema.

What about NoSQL databases? As NoSQL databases vary significantly, we can't make definitive statements. But let's consider a typical document database like MongoDB. Unlike SQL databases, it doesn't enforce a schema. Essentially, you can insert any form of data directly. Often, NoSQL databases support schemaless data, but they lack features that enforce a schema like SQL. They generally support structure via validation methods, rather than structured access.

Is there no choice but to distinguish between structured data and unstructured, schemaless data so clearly? GlueSQL is being developed with the goal of being adaptable in various environments. Being forced to choose regarding this schema constraint was quite inconvenient. We started pondering if we couldn't benefit from both aspects - supporting both schema and schemaless data simultaneously, and we eventually found the answer. Let's look at how GlueSQL currently solves this issue through familiar SQL examples.

CREATE TABLE Names (id INTEGER, name TEXT);
INSERT INTO Names VALUES (1, 'glue'), (2, 'sql');

You can create a regular table with a schema like this. But GlueSQL's choice for creating a schemaless table is as follows:

CREATE TABLE Logs;
INSERT INTO Logs VALUES
('{ "id": 1, "value": 30 }'),
('{ "id": 2, "rate": 3.0, "list": [1, 2, 3] }'),
('{ "id": 3, "rate": 5.0, "value": 100 }');

It creates a table without column definitions! If you do this, GlueSQL recognizes the table as schemaless and processes it internally.

SELECT id, rate, list[0] FROM Logs WHERE id = 2;

Although the way to create the table was a bit special, using it isn't much different from the regular SQL SELECT statement. Not only can you differentiate between schema and schemaless when creating tables, but you can also use them interchangeably!

SELECT * FROM Names JOIN Logs ON Names.id = Logs.id;
/*
| id | list | name | rate | value |
|----|---------|------|------|-------|
| 1 | | glue | | 30 |
| 2 |[1, 2, 3]| sql | 3 | |
*/

Here's an example of querying data by INNER JOINing the Names table, which has a schema, and the Logs table, which is schemaless. GlueSQL has resolved this problem by allowing the internal execution layer to handle both vector-type data, for cases where each row has a defined schema, and map-type data for schemaless cases.

Thanks to this, the variety of storage that can be supported through GlueSQL has expanded significantly. If there were previously limitations to supporting NoSQL databases that support schemaless data, that is no longer the case. The reference storage where you can directly experience this schemaless data support is JSON Storage. It offers features that allow you to deal directly with unstructured data like JSON using GlueSQL.

If GlueSQL starts from the perspective of an SQL database and expands, by providing the AST Builder directly, it once blurs the boundary, and by supporting unstructured data simultaneously, it knocks down the boundary once more. How do you like it?

Decomposing Database Functionality: Breaking Down SQL and NoSQL Features

The distinction between SQL and NoSQL is not just about whether they support unstructured data. Of course, there are examples like unstructured data, which is mainly supported only in NoSQL, but in many cases, SQL databases tend to support more diverse and complex queries. NoSQL often gains other advantages in exchange for reducing the range of query support provided by SQL databases.

GlueSQL is ambitious. It has devised a rather interesting method to support all of this through SQL and the AST Builder, with the same interface. When we usually say SQL database, it implicitly assumes that a lot of features have been fully implemented. Create tables by specifying a schema, modify schemas with "alter table", support both clustered and non-clustered indexes, and support transactions. And there's so much more. But the functionality that is naturally supported in SQL databases may not be natural in other environments.

Let's think about JSON Storage. GlueSQL's JSON Storage allows you to handle JSON, JSONL files using SQL and the AST Builder. This JSON Storage does not support atomic operations or transactions. Of course, it would be great if it did, but implementing and executing them would be a significant performance burden. In most cases, when you want to simply browse and handle JSONL files, the overhead caused by transactions can be an unnecessary burden. In this case, you want to handle JSON, JSONL files using SQL, but you don't necessarily need transactions.

To meet the requirements of these diverse environments, GlueSQL has separated the functionality of what we usually call an SQL database into multiple independent interfaces. +Store, StoreMut, AlterTable, Transaction, .. +These are just a few of the various storage interfaces that GlueSQL currently supports. +The way it works can be summarized like this: +If you implement Store, you can use SELECT. +And if you implement both Store and StoreMut, you can support quite a number of basic SQL statements including SELECT. +You can manage tables with CREATE TABLE, DROP TABLE, and handle data using INSERT, UPDATE, DELETE statements. +If you only need to retrieve data, you only need to implement Store. +If you want to support the ALTER TABLE statement, you can additionally implement the AlterTable interface. +The Transaction interface works the same way. +The interesting part is that, except for Store and StoreMut, all other storage interfaces can be implemented independently. GlueSQL allows you to choose and implement only the features you need. +And it's not just about providing interfaces. It also provides integration tests suitable for each situation to verify what you have implemented. You just need to implement the interface and import the corresponding test case for verification.

In addition to supporting both structured and unstructured data simultaneously, GlueSQL provides the ability to divide the functionality of a database into multiple independent features and selectively implement them. This allows GlueSQL to be ported to a wide variety of environments without any burden.

Conclusion

GlueSQL, while serving as a database that provides its own reference storage, is fundamentally a library designed to simplify the creation of databases. One of the substantial challenges GlueSQL had to overcome in order to support a diverse array of environments was to address the distinctive features that separate conventional SQL databases from NoSQL databases. GlueSQL achieved this through several innovative approaches, managing to support both categories simultaneously despite their significantly different characteristics.

It offers support for SQL alongside an AST Builder, and accommodates both structured and unstructured data. Additionally, it decomposes database functionalities into multiple independent features, allowing each environment to selectively implement the functionalities it requires.

These unique attributes enable GlueSQL to live up to its 'Glue' prefix by facilitating effortless porting across various environments. While we have been developing it for several years, there is still much ground to cover. However, the fact that we are now able to introduce it publicly attests to our successful technological validation and completion of a demonstrable level of implementation.

Through GlueSQL, we hope to provide developers with a unified query interface that can be customized according to their needs, thereby enabling them to produce efficient products more effortlessly. There's a promising future ahead for GlueSQL, and we look forward to its contributions to the technology community.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/blog/tags/tdd/index.html b/docs/0.16.0/blog/tags/tdd/index.html new file mode 100644 index 00000000..c4d83e7d --- /dev/null +++ b/docs/0.16.0/blog/tags/tdd/index.html @@ -0,0 +1,17 @@ + + + + + +One post tagged with "TDD" | GlueSQL + + + + + +
+

One post tagged with "TDD"

View All Tags

· 10 min read
Taehoon Moon

Introduction: GlueSQL and Test-Driven Documentation

Recently, the GlueSQL project reached a significant milestone with the release of version 0.14. This new version brings a host of fresh features to the table, yet one of the most notable changes is in the realm of documentation. For the first time, we're proud to announce the launch of our official documentation website. Interested readers can explore the full range of user manuals at https://gluesql.org/docs.

Prior to this update, the only way to navigate GlueSQL was by manually inspecting the test code within the test suite. With the recent release, however, a comprehensive user manual has been made public to facilitate a more user-friendly experience. We hope that this new addition will prove beneficial to a broad spectrum of users.

The task of compiling an entire database manual in one go was daunting due to the sheer volume of content required. Surprisingly, this process turned out to be smoother than initially anticipated, largely due to the invaluable aid of ChatGPT, which was instrumental in automating much of the document creation. Specifically, around 80% of the SQL Syntax section was generated using this tool.

This remarkable feat was only possible due to the solid foundation of test codes previously established in GlueSQL. In this article, we'll share how we managed to leverage ChatGPT in such a unique way. Based on our recent experience of crafting documents grounded in testing, we've begun to consider the possibility of entirely automating document creation, save for the initial stages.

Along with sharing our journey so far, we will also reveal our plans for future test-based automation of documentation within GlueSQL.

Test Codes and Documentation

The GlueSQL project has placed a significant emphasis on writing test codes. This might be a given for a database project; however, the thoroughness of our approach is evident from our line coverage of nearly 99% for core codes. While we devoted considerable effort to creating these test codes, our primary focus has always been on a different aspect: ensuring that anyone can quickly grasp the content of the tests and easily add new ones.

The intent here is to empower newcomers to GlueSQL to understand the functionality of the software solely by examining integration tests, even in the absence of a user manual.

The integration tests for GlueSQL can be found in the test-suite workspace. For example, here's an excerpt of the test code for the INSERT statement:

test_case!(insert, async move {
run!(
"
CREATE TABLE Test (
id INTEGER DEFAULT 1,
num INTEGER NULL,
name TEXT NOT NULL,
);"
);

test! {
name: "basic insert - single item",
sql: "INSERT INTO Test (id, num, name) VALUES (1, 2, 'Hi boo');",
expected: Ok(Payload::Insert(1))
};


test! {
sql: "INSERT INTO Test VALUES(17, 30, 'Sullivan');",
expected: Ok(Payload::Insert(1))
};

test! {
sql: "INSERT INTO Test (num, name) VALUES (28, 'Wazowski');",
expected: Ok(Payload::Insert(1))
};

test! {
sql: "SELECT * FROM Test;",
expected: Ok(select!(
id | num | name;
I64 | I64 | Str;
1 2 "Hi boo".to_owned();
3 9 "Kitty!".to_owned();
2 7 "Monsters".to_owned();
17 30 "Sullivan".to_owned();
1 28 "Wazowski".to_owned()
))
};

// ...
});

Despite being written in Rust, these test cases are designed to be comprehensible, even to those unfamiliar with the language. Each test is a complete scenario from start to finish, and the results of each operation are readily observable.

Given that identifying results from SELECT operations in the form of Rust enums and structs can be challenging, we actively utilized macros such as select! and select_with_null!. We've composed the test cases to demonstrate that the INSERT statement can handle a wide range of cases, including specifying all columns, omitting some, or omitting all.

test! {
sql: "INSERT INTO Test (id, num) VALUES (1, 10);",
expected: Err(InsertError::LackOfRequiredColumn("name".to_owned()).into())
};

The tests also include scenarios for expected faulty inputs, indicating the error returns in these situations.

By organizing the tests in this manner, we aim to make it easy for anyone to read and write tests. Our goal was for these tests to serve as "documentation" for GlueSQL contributors. At the time we were writing these tests, we didn't anticipate that they could actually become documentation themselves. But we've come to realize that they have extraordinary potential.

Leveraging ChatGPT

When we first embarked on writing the User Manual, we were overwhelmed by the sheer volume of content we had to generate. Around the same time, ChatGPT was gaining prominence, and we thought it might be worth trying out, if only to lighten our load slightly.

To our surprise, ChatGPT exceeded our expectations. If the test codes were well written, it was capable of automatically crafting an exceptional document based on them, capturing all essential details.

After several trials and errors, we settled on the following prompt for document generation. While it's still a challenge to use the same prompt for all documentation, we made minor modifications to suit different situations:

I'm creating an SQL database documentation website, and I'd like you to help me with one of the pages that introduces the SQL syntax for GlueSQL.

1. Please provide the response content in the "markdown" format, so I can copy and paste it directly. Keep this constraint in mind while writing.
2. Regardless of the language I use, I need the content written in English.
3. I will provide some test case code written in the Rust language, which contains SQL examples. Please write the documentation based on these examples, but feel free to change the table names, column names, and data types as needed. Don't include any Rust related content or text in the response. all the response code example should be in plain SQL.
4. GlueSQL does not have the VARCHAR type. If you want to use that, please use TEXT instead. You don't need to mention this in the response.
5. Wrap the entire response text using <pre> and </pre> tags so I can copy all the content easily.

Now, I'd like you to write the following request:
SQL Statement - "INSERT"

Here's an example test code you can refer to:

test_case!(insert, async move {
run!(...

Generally, we used the template above, and copied and pasted the test code from our existing test-suite. We leveraged this method to harness our many tests to assist in the creation of the user manual. In the next section, we'll showcase a sample of the documentation generated in this manner. It's quite impressive.

Success Case: Automated User Manual of GlueSQL

Thanks to ChatGPT, the resulting INSERT document page can be viewed at the following link. It's important to note that we used ChatGPT 4 for this task. Version 3.5 wasn't quite up to the task, and using version 4 was the minimum requirement.

https://gluesql.org/docs/dev/sql-syntax/statements/data-manipulation/insert

INSERT Statement

The results were quite impressive. ChatGPT neatly categorized the test cases, explained the syntax, outlined constraints, and provided appropriate examples. It didn't stop there; it also skillfully recognized error test cases and incorporated them into the documentation, as shown below.

INSERT Statement

Isn't it amazing?

Future Plans: Fully Automating Documentation Generation

While the current documentation is far from perfect and there are many aspects that can be improved, we see great potential in this approach. We believe it's entirely possible to automate the process of writing this kind of document, and writing in general.

In the past, documents like user manuals required a great deal of effort to maintain once they were written. If a document contained real code examples, verifying that the code still worked was often a tedious task. With the ability to automatically generate documentation as we have done here, these issues are no longer problematic.

Previously, you would have to write tests and then also document them separately. If you had to support multiple languages, that would be an additional task. With a tool like ChatGPT, you can automate all of this. All a developer has to do is write the tests. This alone can be sufficient. You can generate documents automatically based on the tests. Eventually, we can even support automatically translating these documents into multiple languages.

The GlueSQL project repository is currently hosted on GitHub and makes good use of various GitHub Actions. We envision a GitHub Action that automatically regenerates a document corresponding to a test when a user modifies the test and raises a Pull Request. Another GitHub Action could automatically translate updated documents into supported languages and create new Pull Requests. The possibilities are truly endless.

Not only will this help with document generation, but it will also provide clear guidelines for writing better test code. If we can automatically generate documents based on written tests, the quality of those documents can serve as an indicator of the quality of the tests themselves. This means that a document automation tool can play the role of a good reviewer for tests. It can greatly reduce the time and effort required for painstakingly reviewing the quality of each test. Developers can also write tests without pressure, evaluate their test code by looking at the generated document, and improve it.

Furthermore, multi-language support becomes a breeze. In my personal experience as a software engineer over the past decade, developing various products such as games, web services, and applications, I often needed to support multiple languages. Each time, there was no definite solution. The optimal approach varied depending on the situation, and there were many things to consider when entrusting translations, such as effectively communicating the context of the target service to the translator. Moreover, regularly updating content and having it retranslated into various languages was a very tedious process. While I tried to automate as much as possible by creating various tools, I was never fully satisfied. I believe ChatGPT can completely solve these issues. If there is a need to provide project-specific context, all you need to do is prepare a prompt in advance. Instead of having to rely on and wait for professional translators, we can now entrust this task to ChatGPT, and we only need a few people to review the translated content.

We are nearing a world where documentation is no longer a burden for developers.

Conclusion: The Value of Test-Driven Documentation

The use of ChatGPT to generate documentation has proven a significant step forward in the GlueSQL user manual creation process. Through test-driven documentation, we've managed to automate a substantial part of the manual creation process, saving time and effort, and increasing accuracy.

Moreover, this process has unveiled a new potential for documentation: the possibility of fully automating document generation. We've seen that quality tests can become quality documentation with the help of AI, leading to more efficient workflows and possibly better test code as a result.

The journey doesn't stop here. We envision leveraging this capability further to auto-translate our documents into multiple languages, making our product more accessible to a global audience.

As we progress, we hope that our experience can inspire other developers to explore and embrace the benefits of AI-generated, test-driven documentation. It's not just about saving time—it's about improving the way we work, communicate, and share knowledge.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/blog/tags/test-driven-documentation/index.html b/docs/0.16.0/blog/tags/test-driven-documentation/index.html new file mode 100644 index 00000000..ab63f320 --- /dev/null +++ b/docs/0.16.0/blog/tags/test-driven-documentation/index.html @@ -0,0 +1,17 @@ + + + + + +One post tagged with "Test-Driven-Documentation" | GlueSQL + + + + + +
+

One post tagged with "Test-Driven-Documentation"

View All Tags

· 10 min read
Taehoon Moon

Introduction: GlueSQL and Test-Driven Documentation

Recently, the GlueSQL project reached a significant milestone with the release of version 0.14. This new version brings a host of fresh features to the table, yet one of the most notable changes is in the realm of documentation. For the first time, we're proud to announce the launch of our official documentation website. Interested readers can explore the full range of user manuals at https://gluesql.org/docs.

Prior to this update, the only way to navigate GlueSQL was by manually inspecting the test code within the test suite. With the recent release, however, a comprehensive user manual has been made public to facilitate a more user-friendly experience. We hope that this new addition will prove beneficial to a broad spectrum of users.

The task of compiling an entire database manual in one go was daunting due to the sheer volume of content required. Surprisingly, this process turned out to be smoother than initially anticipated, largely due to the invaluable aid of ChatGPT, which was instrumental in automating much of the document creation. Specifically, around 80% of the SQL Syntax section was generated using this tool.

This remarkable feat was only possible due to the solid foundation of test codes previously established in GlueSQL. In this article, we'll share how we managed to leverage ChatGPT in such a unique way. Based on our recent experience of crafting documents grounded in testing, we've begun to consider the possibility of entirely automating document creation, save for the initial stages.

Along with sharing our journey so far, we will also reveal our plans for future test-based automation of documentation within GlueSQL.

Test Codes and Documentation

The GlueSQL project has placed a significant emphasis on writing test codes. This might be a given for a database project; however, the thoroughness of our approach is evident from our line coverage of nearly 99% for core codes. While we devoted considerable effort to creating these test codes, our primary focus has always been on a different aspect: ensuring that anyone can quickly grasp the content of the tests and easily add new ones.

The intent here is to empower newcomers to GlueSQL to understand the functionality of the software solely by examining integration tests, even in the absence of a user manual.

The integration tests for GlueSQL can be found in the test-suite workspace. For example, here's an excerpt of the test code for the INSERT statement:

test_case!(insert, async move {
run!(
"
CREATE TABLE Test (
id INTEGER DEFAULT 1,
num INTEGER NULL,
name TEXT NOT NULL,
);"
);

test! {
name: "basic insert - single item",
sql: "INSERT INTO Test (id, num, name) VALUES (1, 2, 'Hi boo');",
expected: Ok(Payload::Insert(1))
};


test! {
sql: "INSERT INTO Test VALUES(17, 30, 'Sullivan');",
expected: Ok(Payload::Insert(1))
};

test! {
sql: "INSERT INTO Test (num, name) VALUES (28, 'Wazowski');",
expected: Ok(Payload::Insert(1))
};

test! {
sql: "SELECT * FROM Test;",
expected: Ok(select!(
id | num | name;
I64 | I64 | Str;
1 2 "Hi boo".to_owned();
3 9 "Kitty!".to_owned();
2 7 "Monsters".to_owned();
17 30 "Sullivan".to_owned();
1 28 "Wazowski".to_owned()
))
};

// ...
});

Despite being written in Rust, these test cases are designed to be comprehensible, even to those unfamiliar with the language. Each test is a complete scenario from start to finish, and the results of each operation are readily observable.

Given that identifying results from SELECT operations in the form of Rust enums and structs can be challenging, we actively utilized macros such as select! and select_with_null!. We've composed the test cases to demonstrate that the INSERT statement can handle a wide range of cases, including specifying all columns, omitting some, or omitting all.

test! {
sql: "INSERT INTO Test (id, num) VALUES (1, 10);",
expected: Err(InsertError::LackOfRequiredColumn("name".to_owned()).into())
};

The tests also include scenarios for expected faulty inputs, indicating the error returns in these situations.

By organizing the tests in this manner, we aim to make it easy for anyone to read and write tests. Our goal was for these tests to serve as "documentation" for GlueSQL contributors. At the time we were writing these tests, we didn't anticipate that they could actually become documentation themselves. But we've come to realize that they have extraordinary potential.

Leveraging ChatGPT

When we first embarked on writing the User Manual, we were overwhelmed by the sheer volume of content we had to generate. Around the same time, ChatGPT was gaining prominence, and we thought it might be worth trying out, if only to lighten our load slightly.

To our surprise, ChatGPT exceeded our expectations. If the test codes were well written, it was capable of automatically crafting an exceptional document based on them, capturing all essential details.

After several trials and errors, we settled on the following prompt for document generation. While it's still a challenge to use the same prompt for all documentation, we made minor modifications to suit different situations:

I'm creating an SQL database documentation website, and I'd like you to help me with one of the pages that introduces the SQL syntax for GlueSQL.

1. Please provide the response content in the "markdown" format, so I can copy and paste it directly. Keep this constraint in mind while writing.
2. Regardless of the language I use, I need the content written in English.
3. I will provide some test case code written in the Rust language, which contains SQL examples. Please write the documentation based on these examples, but feel free to change the table names, column names, and data types as needed. Don't include any Rust related content or text in the response. all the response code example should be in plain SQL.
4. GlueSQL does not have the VARCHAR type. If you want to use that, please use TEXT instead. You don't need to mention this in the response.
5. Wrap the entire response text using <pre> and </pre> tags so I can copy all the content easily.

Now, I'd like you to write the following request:
SQL Statement - "INSERT"

Here's an example test code you can refer to:

test_case!(insert, async move {
run!(...

Generally, we used the template above, and copied and pasted the test code from our existing test-suite. We leveraged this method to harness our many tests to assist in the creation of the user manual. In the next section, we'll showcase a sample of the documentation generated in this manner. It's quite impressive.

Success Case: Automated User Manual of GlueSQL

Thanks to ChatGPT, the resulting INSERT document page can be viewed at the following link. It's important to note that we used ChatGPT 4 for this task. Version 3.5 wasn't quite up to the task, and using version 4 was the minimum requirement.

https://gluesql.org/docs/dev/sql-syntax/statements/data-manipulation/insert

INSERT Statement

The results were quite impressive. ChatGPT neatly categorized the test cases, explained the syntax, outlined constraints, and provided appropriate examples. It didn't stop there; it also skillfully recognized error test cases and incorporated them into the documentation, as shown below.

INSERT Statement

Isn't it amazing?

Future Plans: Fully Automating Documentation Generation

While the current documentation is far from perfect and there are many aspects that can be improved, we see great potential in this approach. We believe it's entirely possible to automate the process of writing this kind of document, and writing in general.

In the past, documents like user manuals required a great deal of effort to maintain once they were written. If a document contained real code examples, verifying that the code still worked was often a tedious task. With the ability to automatically generate documentation as we have done here, these issues are no longer problematic.

Previously, you would have to write tests and then also document them separately. If you had to support multiple languages, that would be an additional task. With a tool like ChatGPT, you can automate all of this. All a developer has to do is write the tests. This alone can be sufficient. You can generate documents automatically based on the tests. Eventually, we can even support automatically translating these documents into multiple languages.

The GlueSQL project repository is currently hosted on GitHub and makes good use of various GitHub Actions. We envision a GitHub Action that automatically regenerates a document corresponding to a test when a user modifies the test and raises a Pull Request. Another GitHub Action could automatically translate updated documents into supported languages and create new Pull Requests. The possibilities are truly endless.

Not only will this help with document generation, but it will also provide clear guidelines for writing better test code. If we can automatically generate documents based on written tests, the quality of those documents can serve as an indicator of the quality of the tests themselves. This means that a document automation tool can play the role of a good reviewer for tests. It can greatly reduce the time and effort required for painstakingly reviewing the quality of each test. Developers can also write tests without pressure, evaluate their test code by looking at the generated document, and improve it.

Furthermore, multi-language support becomes a breeze. In my personal experience as a software engineer over the past decade, developing various products such as games, web services, and applications, I often needed to support multiple languages. Each time, there was no definite solution. The optimal approach varied depending on the situation, and there were many things to consider when entrusting translations, such as effectively communicating the context of the target service to the translator. Moreover, regularly updating content and having it retranslated into various languages was a very tedious process. While I tried to automate as much as possible by creating various tools, I was never fully satisfied. I believe ChatGPT can completely solve these issues. If there is a need to provide project-specific context, all you need to do is prepare a prompt in advance. Instead of having to rely on and wait for professional translators, we can now entrust this task to ChatGPT, and we only need a few people to review the translated content.

We are nearing a world where documentation is no longer a burden for developers.

Conclusion: The Value of Test-Driven Documentation

The use of ChatGPT to generate documentation has proven a significant step forward in the GlueSQL user manual creation process. Through test-driven documentation, we've managed to automate a substantial part of the manual creation process, saving time and effort, and increasing accuracy.

Moreover, this process has unveiled a new potential for documentation: the possibility of fully automating document generation. We've seen that quality tests can become quality documentation with the help of AI, leading to more efficient workflows and possibly better test code as a result.

The journey doesn't stop here. We envision leveraging this capability further to auto-translate our documents into multiple languages, making our product more accessible to a global audience.

As we progress, we hope that our experience can inspire other developers to explore and embrace the benefits of AI-generated, test-driven documentation. It's not just about saving time—it's about improving the way we work, communicate, and share knowledge.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/blog/tags/v-0-14/index.html b/docs/0.16.0/blog/tags/v-0-14/index.html new file mode 100644 index 00000000..b8050e34 --- /dev/null +++ b/docs/0.16.0/blog/tags/v-0-14/index.html @@ -0,0 +1,19 @@ + + + + + +One post tagged with "v0.14" | GlueSQL + + + + + +
+

One post tagged with "v0.14"

View All Tags

· 11 min read
Taehoon Moon

We now provide an official documentation website at https://gluesql.org/docs

🚀 Features

🍀 Schemaless data support

GlueSQL now supports creating tables without a schema, allowing for both structured and unstructured data to be stored in the same table. +To create a schemaless table, simply run CREATE TABLE without specifying any columns. For more information on querying schemaless data, please refer to the following link: querying schemaless data

CREATE TABLE Bar;

To insert values,

INSERT INTO Bar VALUES
('{ "name": "ast", "value": 30 }'),
('{ "name": "glue", "rate": 3.0, "list": [1, 2, 3] }'),

Then, selecting values from schemaless table is simple.

SELECT name, rate, list[0] FROM Bar WHERE name = 'glue';

e.g.

CREATE TABLE Names (id INTEGER, name TEXT);
INSERT INTO Names VALUES (1, 'glue'), (2, 'sql');

CREATE TABLE Logs;
INSERT INTO Logs VALUES
('{ "id": 1, "value": 30 }'),
('{ "id": 2, "rate": 3.0, "list": [1, 2, 3] }'),
('{ "id": 3, "rate": 5.0, "value": 100 }');

SELECT * FROM Names JOIN Logs ON Names.id = Logs.id;
/*
| id | list | name | rate | value |
|----|---------|------|------|-------|
| 1 | | glue | | 30 |
| 2 |[1, 2, 3]| sql | 3 | |
*/

🍀 IndexedDB & WebStorage supports in JavaScript package

GlueSQL supports handling in-memory, localStorage, sessionStorage, and even IndexedDB using the same SQL syntax. All you need to know is how to specify the ENGINE when creating a table.

e.g.

CREATE TABLE Mem (mid INTEGER) ENGINE = memory;
CREATE TABLE Loc (lid INTEGER) ENGINE = localStorage;
CREATE TABLE Ses (sid INTEGER) ENGINE = sessionStorage;
CREATE TABLE Idb (iid INTEGER) ENGINE = indexedDB;

SELECT
mid, lid, sid, iid
FROM Mem
JOIN Loc
JOIN Ses
JOIN Idb;

🍀 Data Types - UINT32, UINT64, UINT128, POINT and FLOAT32

🍀 Functions - APPEND, PREPEND, RAND, FIND_IDX, INITCAP and CALC_DISTANCE

🍀 Store traits

User-level custom function

By implementing both the CustomFunction and CustomFunctionMut traits, users can create, use, and delete user-level custom functions. Although GlueSQL plans to continuously add various functions, users may still find them insufficient. In such cases, users can create their own user-level custom functions to supplement the built-in functions. Additionally, if there are repetitive business logic codes, they can be stored as custom functions. +e.g.

CREATE FUNCTION ADD_ONE (n INT, x INT DEFAULT 1) RETURN n + x;

SELECT ADD_ONE(10) AS test;

DROP FUNCTION ADD_ONE;

Metadata

The Metadata trait is an optional implementation for providing additional metadata support in GlueSQL. GlueSQL does not enforce any specific metadata implementation, allowing custom storage developers to decide which type of metadata, such as create time, modify time, etc., they want to provide.

🍀 Storages

JSON Storage

Composite Storage

  • Add CompositeStorage which bundles multiple storages @panarch (#1068)

IndexedDB Storage

Web Storage

  • Add WebStorage - support localStorage \& sessionStorage for web browsers @panarch (#1050)

🍀 Other new features

🌊 Interface Changes

  • Remove Store trait related cfg features, @panarch (#1091)
  • Refactor CreateTable.columns from Vec<ColumnDef> to Option<Vec<ColumnDef>> @devgony (#1086)
  • Remove MutResult @panarch (#1073)
  • Update all store mut trait methods to take \&mut self @panarch (#1072)
  • Change StoreMut interface to use \&mut self, not to take ownership @panarch (#1071)
  • Modify default ColumnOption from NOT NULL to NULL @devgony (#997)

🌟 Improvements

🌳 Documentation

We now provide an official documentation website at https://gluesql.org/docs

Docs - setup

📋 Tests

🐛 Bug Fixes

  • Fix docusaurus pages/index broken link @panarch (#1214)
  • Fix docs/ Discord GlueSQL channel invite link address @panarch (#1213)
  • Fix InvalidJsonString error message replacing payload to fileName @devgony (#1185)
  • Fix TryFrom Value::Str to u128 not to use parse_uuid @ChobobDev (#1134)
  • Fix column alias with identifer for TableFactor::Derived @ding-young (#1119)
  • Pass data even when deleted_by is not present @ever0de (#1117)
  • Fix MemoryStorage \& WebStorage primary key support @panarch (#1115)
  • Fix plan::validate to handle CTAS and ITAS adding unit test @devgony (#1074)
  • Fix test-suite tester functions to show (found, expected) shape @panarch (#1028)
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/blog/tags/v-0-15/index.html b/docs/0.16.0/blog/tags/v-0-15/index.html new file mode 100644 index 00000000..63bf2e66 --- /dev/null +++ b/docs/0.16.0/blog/tags/v-0-15/index.html @@ -0,0 +1,17 @@ + + + + + +One post tagged with "v0.15" | GlueSQL + + + + + +
+

One post tagged with "v0.15"

View All Tags

· 6 min read
Taehoon Moon

🌊 Breaking Changes

🍀 Python Support

Code Samples

from gluesql import Glue, MemoryStorage
from tabulate import tabulate

db = Glue(MemoryStorage())

sql = """
SELECT
u.name as user,
d.name as device
FROM User u
JOIN Device d ON u.id = d.userId
""".strip().replace(
" ", ""
)

result = db.query(sql)
rows = result[0].get("rows")
print(f"\n[Query]\n{sql}")
print(tabulate(rows, headers="keys", showindex=True, tablefmt="simple_outline"))

🍀 Redis Storage

🍀 CSV Storage

🍀 More operators and functions

🚀 Features

  • feat: implement select iterator utility function @ever0de (#1429)

🌟 Improvements

🐛 Bug Fixes

  • fix: Literal comparison with BinaryOperator @ding-co (#1397)
  • fix: update Key.cmp to compare a type with other type @tgsong827 (#1367)
  • Fix Value::evaluate_cmp_with_literal between Decimal and Literal::Num… @panarch (#1352)
  • Fix spool on tabular off and SelectMap @devgony (#1314)
  • Update auto-assign-action to be triggered on PR open from fork repos @panarch (#1313)
  • Fix Scala Subquery should contain only 1 column @ChobobDev (#1284)
  • Wrap config path by quotes in auto-author-assign.yml @panarch (#1258)
  • Apply word-wrap to docs/ article h1 @panarch (#1230)
  • Fix docusaurus.config.js themeConfig handler @panarch (#1225)

👏 New Contributors

Full Changelog: https://github.com/gluesql/gluesql/compare/v0.14.0...v0.15.0

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/blog/test-driven-documentation/index.html b/docs/0.16.0/blog/test-driven-documentation/index.html new file mode 100644 index 00000000..5b9f8e87 --- /dev/null +++ b/docs/0.16.0/blog/test-driven-documentation/index.html @@ -0,0 +1,17 @@ + + + + + +Test-Driven Documentation - Automating User Manual Creation in GlueSQL | GlueSQL + + + + + +
+

Test-Driven Documentation - Automating User Manual Creation in GlueSQL

· 10 min read
Taehoon Moon

Introduction: GlueSQL and Test-Driven Documentation

Recently, the GlueSQL project reached a significant milestone with the release of version 0.14. This new version brings a host of fresh features to the table, yet one of the most notable changes is in the realm of documentation. For the first time, we're proud to announce the launch of our official documentation website. Interested readers can explore the full range of user manuals at https://gluesql.org/docs.

Prior to this update, the only way to navigate GlueSQL was by manually inspecting the test code within the test suite. With the recent release, however, a comprehensive user manual has been made public to facilitate a more user-friendly experience. We hope that this new addition will prove beneficial to a broad spectrum of users.

The task of compiling an entire database manual in one go was daunting due to the sheer volume of content required. Surprisingly, this process turned out to be smoother than initially anticipated, largely due to the invaluable aid of ChatGPT, which was instrumental in automating much of the document creation. Specifically, around 80% of the SQL Syntax section was generated using this tool.

This remarkable feat was only possible due to the solid foundation of test codes previously established in GlueSQL. In this article, we'll share how we managed to leverage ChatGPT in such a unique way. Based on our recent experience of crafting documents grounded in testing, we've begun to consider the possibility of entirely automating document creation, save for the initial stages.

Along with sharing our journey so far, we will also reveal our plans for future test-based automation of documentation within GlueSQL.

Test Codes and Documentation

The GlueSQL project has placed a significant emphasis on writing test codes. This might be a given for a database project; however, the thoroughness of our approach is evident from our line coverage of nearly 99% for core codes. While we devoted considerable effort to creating these test codes, our primary focus has always been on a different aspect: ensuring that anyone can quickly grasp the content of the tests and easily add new ones.

The intent here is to empower newcomers to GlueSQL to understand the functionality of the software solely by examining integration tests, even in the absence of a user manual.

The integration tests for GlueSQL can be found in the test-suite workspace. For example, here's an excerpt of the test code for the INSERT statement:

test_case!(insert, async move {
run!(
"
CREATE TABLE Test (
id INTEGER DEFAULT 1,
num INTEGER NULL,
name TEXT NOT NULL,
);"
);

test! {
name: "basic insert - single item",
sql: "INSERT INTO Test (id, num, name) VALUES (1, 2, 'Hi boo');",
expected: Ok(Payload::Insert(1))
};


test! {
sql: "INSERT INTO Test VALUES(17, 30, 'Sullivan');",
expected: Ok(Payload::Insert(1))
};

test! {
sql: "INSERT INTO Test (num, name) VALUES (28, 'Wazowski');",
expected: Ok(Payload::Insert(1))
};

test! {
sql: "SELECT * FROM Test;",
expected: Ok(select!(
id | num | name;
I64 | I64 | Str;
1 2 "Hi boo".to_owned();
3 9 "Kitty!".to_owned();
2 7 "Monsters".to_owned();
17 30 "Sullivan".to_owned();
1 28 "Wazowski".to_owned()
))
};

// ...
});

Despite being written in Rust, these test cases are designed to be comprehensible, even to those unfamiliar with the language. Each test is a complete scenario from start to finish, and the results of each operation are readily observable.

Given that identifying results from SELECT operations in the form of Rust enums and structs can be challenging, we actively utilized macros such as select! and select_with_null!. We've composed the test cases to demonstrate that the INSERT statement can handle a wide range of cases, including specifying all columns, omitting some, or omitting all.

test! {
sql: "INSERT INTO Test (id, num) VALUES (1, 10);",
expected: Err(InsertError::LackOfRequiredColumn("name".to_owned()).into())
};

The tests also include scenarios for expected faulty inputs, indicating the error returns in these situations.

By organizing the tests in this manner, we aim to make it easy for anyone to read and write tests. Our goal was for these tests to serve as "documentation" for GlueSQL contributors. At the time we were writing these tests, we didn't anticipate that they could actually become documentation themselves. But we've come to realize that they have extraordinary potential.

Leveraging ChatGPT

When we first embarked on writing the User Manual, we were overwhelmed by the sheer volume of content we had to generate. Around the same time, ChatGPT was gaining prominence, and we thought it might be worth trying out, if only to lighten our load slightly.

To our surprise, ChatGPT exceeded our expectations. If the test codes were well written, it was capable of automatically crafting an exceptional document based on them, capturing all essential details.

After several trials and errors, we settled on the following prompt for document generation. While it's still a challenge to use the same prompt for all documentation, we made minor modifications to suit different situations:

I'm creating an SQL database documentation website, and I'd like you to help me with one of the pages that introduces the SQL syntax for GlueSQL.

1. Please provide the response content in the "markdown" format, so I can copy and paste it directly. Keep this constraint in mind while writing.
2. Regardless of the language I use, I need the content written in English.
3. I will provide some test case code written in the Rust language, which contains SQL examples. Please write the documentation based on these examples, but feel free to change the table names, column names, and data types as needed. Don't include any Rust related content or text in the response. all the response code example should be in plain SQL.
4. GlueSQL does not have the VARCHAR type. If you want to use that, please use TEXT instead. You don't need to mention this in the response.
5. Wrap the entire response text using <pre> and </pre> tags so I can copy all the content easily.

Now, I'd like you to write the following request:
SQL Statement - "INSERT"

Here's an example test code you can refer to:

test_case!(insert, async move {
run!(...

Generally, we used the template above, and copied and pasted the test code from our existing test-suite. We leveraged this method to harness our many tests to assist in the creation of the user manual. In the next section, we'll showcase a sample of the documentation generated in this manner. It's quite impressive.

Success Case: Automated User Manual of GlueSQL

Thanks to ChatGPT, the resulting INSERT document page can be viewed at the following link. It's important to note that we used ChatGPT 4 for this task. Version 3.5 wasn't quite up to the task, and using version 4 was the minimum requirement.

https://gluesql.org/docs/dev/sql-syntax/statements/data-manipulation/insert

INSERT Statement

The results were quite impressive. ChatGPT neatly categorized the test cases, explained the syntax, outlined constraints, and provided appropriate examples. It didn't stop there; it also skillfully recognized error test cases and incorporated them into the documentation, as shown below.

INSERT Statement

Isn't it amazing?

Future Plans: Fully Automating Documentation Generation

While the current documentation is far from perfect and there are many aspects that can be improved, we see great potential in this approach. We believe it's entirely possible to automate the process of writing this kind of document, and writing in general.

In the past, documents like user manuals required a great deal of effort to maintain once they were written. If a document contained real code examples, verifying that the code still worked was often a tedious task. With the ability to automatically generate documentation as we have done here, these issues are no longer problematic.

Previously, you would have to write tests and then also document them separately. If you had to support multiple languages, that would be an additional task. With a tool like ChatGPT, you can automate all of this. All a developer has to do is write the tests. This alone can be sufficient. You can generate documents automatically based on the tests. Eventually, we can even support automatically translating these documents into multiple languages.

The GlueSQL project repository is currently hosted on GitHub and makes good use of various GitHub Actions. We envision a GitHub Action that automatically regenerates a document corresponding to a test when a user modifies the test and raises a Pull Request. Another GitHub Action could automatically translate updated documents into supported languages and create new Pull Requests. The possibilities are truly endless.

Not only will this help with document generation, but it will also provide clear guidelines for writing better test code. If we can automatically generate documents based on written tests, the quality of those documents can serve as an indicator of the quality of the tests themselves. This means that a document automation tool can play the role of a good reviewer for tests. It can greatly reduce the time and effort required for painstakingly reviewing the quality of each test. Developers can also write tests without pressure, evaluate their test code by looking at the generated document, and improve it.

Furthermore, multi-language support becomes a breeze. In my personal experience as a software engineer over the past decade, developing various products such as games, web services, and applications, I often needed to support multiple languages. Each time, there was no definite solution. The optimal approach varied depending on the situation, and there were many things to consider when entrusting translations, such as effectively communicating the context of the target service to the translator. Moreover, regularly updating content and having it retranslated into various languages was a very tedious process. While I tried to automate as much as possible by creating various tools, I was never fully satisfied. I believe ChatGPT can completely solve these issues. If there is a need to provide project-specific context, all you need to do is prepare a prompt in advance. Instead of having to rely on and wait for professional translators, we can now entrust this task to ChatGPT, and we only need a few people to review the translated content.

We are nearing a world where documentation is no longer a burden for developers.

Conclusion: The Value of Test-Driven Documentation

The use of ChatGPT to generate documentation has proven a significant step forward in the GlueSQL user manual creation process. Through test-driven documentation, we've managed to automate a substantial part of the manual creation process, saving time and effort, and increasing accuracy.

Moreover, this process has unveiled a new potential for documentation: the possibility of fully automating document generation. We've seen that quality tests can become quality documentation with the help of AI, leading to more efficient workflows and possibly better test code as a result.

The journey doesn't stop here. We envision leveraging this capability further to auto-translate our documents into multiple languages, making our product more accessible to a global audience.

As we progress, we hope that our experience can inspire other developers to explore and embrace the benefits of AI-generated, test-driven documentation. It's not just about saving time—it's about improving the way we work, communicate, and share knowledge.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/getting-started/cli/index.html b/docs/0.16.0/getting-started/cli/index.html new file mode 100644 index 00000000..3b893f8e --- /dev/null +++ b/docs/0.16.0/getting-started/cli/index.html @@ -0,0 +1,17 @@ + + + + + +Command-Line Interface | GlueSQL + + + + + +
+

Command-Line Interface

Introduction

The Command-Line Interface (CLI) is a tool that allows interactive execution of SQL on GlueSQL. It supports Dot commands for more convenient use, and the .edit command allows immediate modification of query files, which can then be executed with .execute. In addition, it supports HTML table format output for SQL results, making it possible to use the results directly on the web.

Installation

To install the GlueSQL Command-Line Interface (CLI), run the following command:

$ cargo install gluesql

Running the CLI

Once you have installed the GlueSQL CLI, you can use it to interact with your database. The CLI has several options that you can use to customize your database configuration:

$ gluesql [--execute ~/sql_path] [--path ~/data_path --storage={sled | json}]

--execute

This option allows you to execute a SQL query that is stored in a specific file path. You need to provide the path to the SQL file that contains the query you want to execute. For example, you can use the following command to execute a file located at ~/sql_path/query.sql

gluesql --execute ~/sql_path/query.sql

--path

This option allows you to specify the path to your database's data directory. By default, GlueSQL stores your database in the current directory. However, you can use the --path option to specify a custom directory where you want to store your database files. For example, you can use the following command to specify a custom data directory ~/mydatabase:

gluesql --path ~/mydatabase

--storage

This option allows you to specify the storage engine you want to use for your database. By default, GlueSQL uses the memory storage engine. However, you can also use sled or json storage engine by using the --storage option. Note that sled and json should be with --path option. For example, you can use the following command to specify the json storage engine:

gluesql --path ~/mydatabase --storage=json

Dot command

.show

This command shows current Print options.

gluesql> .show all
tabular ON
colsep "|"
colwrap ""
heading ON

or you can specify a option

gluesql> .show colsep
colsep "|"

.set

This command can set each Print options

commanddescription
tabular {ON|OFF}turn on/off html table format
colsep {SEPARATOR}set column separator(tabular OFF only)
colwrap {WRAPPER}set column wrapper(tabular OFF only)
heading {ON|OFF}turn on/off heading
gluesql> VALUES (1, 'Glue'), (2, 'SQL');
| column1 | column2 |
|---------|---------|
| 1 | Glue |
| 2 | SQL |

gluesql> .set tabular off
gluesql> VALUES (1, 'Glue'), (2, 'SQL');
column1|column2
1|Glue
2|SQL
gluesql> .set colsep ,
gluesql> VALUES (1, 'Glue'), (2, 'SQL');
column1,column2
1,Glue
2,SQL
gluesql> .set colwrap '
gluesql> VALUES (1, 'Glue'), (2, 'SQL');
'column1','column2'
'1','Glue'
'2','SQL'
gluesql> .set heading off
gluesql> VALUES (1, 'Glue'), (2, 'SQL');
'1','Glue'
'2','SQL'

.edit

This command open editor with last executed SQL or PATH

With last executed SQL

if you execute .edit, it opens specified (set on $EDITOR env) or OS default editor.

$ export $EDITOR=vi
$ gluesql
gluesql> VALUES (1, 'Glue'), (2, 'SQL');
| column1 | column2 |
|---------|---------|
| 1 | Glue |
| 2 | SQL |
gluesql> .edit

Last executed SQL is opened with vi

--! /tmp/Glue_xxxxx.sql
VALUES (1, 'Glue'), (2, 'SQL');

With PATH

gluesql> .edit insert.sql

It opens editor and shows the contents of create_insert.sql

--! create_insert.sql
CREATE TABLE Items (id INT, name TEXT);
INSERT INTO Items VALUES (1, 'Glue'), (2, 'SQL');

.execute

This command executes SQL from PATH

gluesql> .execute create_insert.sql
Table created

2 rows inserted

.run

This command executes last executed command again.

gluesql> VALUES (1, 'Glue'), (2, 'SQL');
| column1 | column2 |
|---------|---------|
| 1 | Glue |
| 2 | SQL |

gluesql> .run
| column1 | column2 |
|---------|---------|
| 1 | Glue |
| 2 | SQL |

Also possible to combinate with .edit

gluesql> VALUES (1, 'Glue'), (2, 'SQL');
| column1 | column2 |
|---------|---------|
| 1 | Glue |
| 2 | SQL |

gluesql> .edit

edit to add (3, 'Rust')

--! /tmp/Glue_xxxxxx.sql
VALUES (1, 'Glue'), (2, 'SQL'), (3, 'Rust')
gluesql> .run
| column1 | column2 |
|---------|---------|
| 1 | Glue |
| 2 | SQL |
| 3 | Rust |

More commands

If you execute .help, you can see various helper command starting with dot(.)

commanddescription
.helpshow help
.quitquit program
.tablesshow table names
.functionsshow function names
.columns TABLEshow columns from TABLE
.versionshow version
.execute PATHexecute SQL from PATH
.spool PATH|offspool to PATH or off
.show OPTIONshow print option eg).show all
.set OPTIONset print option eg).set tabular off
.edit [PATH]open editor with last command or PATH
.runexecute last command

Migration using CLI

GlueSQL CLI supports generating SQL scripts for dumping whole schemas and data.

For instance, if you want to dump your database schema and data to a file named dump.sql, you can use the following command:

$ gluesql --path ~/glue_data --dump ./dump.sql

This will create a SQL script in the current directory that you can use to recreate your database.

If you want to import the database from the dump.sql file, you can use the following command:

$ gluesql --execute ./dump.sql --path ~/new_data --storage=sled

This will create a new database in the specified path, using the Sled Storage engine.

That's it! You now know how to use GlueSQL to migrate your database schema and data using the CLI.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/getting-started/javascript-web/index.html b/docs/0.16.0/getting-started/javascript-web/index.html new file mode 100644 index 00000000..5a706a8c --- /dev/null +++ b/docs/0.16.0/getting-started/javascript-web/index.html @@ -0,0 +1,17 @@ + + + + + +JavaScript (Web Browser) | GlueSQL + + + + + +
+

JavaScript (Web Browser)

GlueSQL is a SQL database engine written in Rust, compiled to WebAssembly, and can be used in JavaScript. This guide will walk you through the process of installing and using the GlueSQL package.

Installation

Installing GlueSQL is as simple as running the following command:

npm install gluesql

In your package.json, it will be added to the dependencies list as follows:

{
"dependencies": {
"gluesql": "latest"
}
}

Usage

GlueSQL can be used in different environments. Here we will look at how to use it with JavaScript modules, Webpack, and Rollup.

JavaScript Modules

In an HTML file, you can use GlueSQL by importing it with a script tag:

<script type="module">
import { gluesql } from 'gluesql';

async function main() {
const db = await gluesql();
await db.loadIndexedDB();

const result = await db.query(`
CREATE TABLE Foo (id INTEGER) ENGINE = memory;
INSERT INTO Foo (1, 'glue'), (2, 'sql');
SELECT * FROM Foo;
`);

console.log(result);
}
</script>

Webpack

For Webpack, the usage is almost the same as JavaScript modules:

import { gluesql } from 'gluesql';

async function run() {
const db = await gluesql();
await db.loadIndexedDB();

const result = await db.query(`
CREATE TABLE Foo (id INTEGER) ENGINE = memory;
INSERT INTO Foo VALUES (1, 'glue'), (2, 'sql');
SELECT * FROM Foo;
`);

console.log(result);
}

Rollup

For Rollup, you need to adjust your import statement and add some configurations to your rollup.config.js file.

First, modify your import statement as follows:

import { gluesql } from 'gluesql/gluesql.rollup';
// ...

Second, add the following configurations to your rollup.config.js file:

import resolve from '@rollup/plugin-node-resolve';
import { wasm } from '@rollup/plugin-wasm';

export default {
input: 'main.js',
output: {
file: 'dist/bundle.js',
format: 'iife',
},
plugins: [
resolve({ browser: true }),
wasm({ targetEnv: 'auto-inline' }),
],
};

These configurations allow Rollup to correctly handle WebAssembly modules and resolve dependencies for browsers.

Don't forget to run the rollup command to bundle your JavaScript files:

rollup -c

Now, you can use GlueSQL in your Rollup project as you would in any other JavaScript module.

Supported Storage Engines

GlueSQL supports four storage types: In-Memory Storage, Local Storage, Session Storage, and IndexedDB.

You can specify the storage type when creating a table using the ENGINE clause:

  • For In-Memory Storage: ENGINE = memory
  • For Local Storage: ENGINE = localStorage
  • For Session Storage: ENGINE = sessionStorage
  • For IndexedDB: ENGINE = indexedDB

For example:

CREATE TABLE Foo (id INTEGER) ENGINE = memory;
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/getting-started/nodejs/index.html b/docs/0.16.0/getting-started/nodejs/index.html new file mode 100644 index 00000000..8874775c --- /dev/null +++ b/docs/0.16.0/getting-started/nodejs/index.html @@ -0,0 +1,17 @@ + + + + + +Node.js | GlueSQL + + + + + +
+

Node.js

This guide will help you get started with GlueSQL in a Node.js project. First, install the gluesql package using npm by running the following command in your terminal:

npm install gluesql

Alternatively, you can add it as a dependency in your package.json file:

{
"dependencies": {
"gluesql": "latest"
}
}

Please note that the Node.js version of GlueSQL currently supports only non-persistent memory storage.

Next, you can use GlueSQL in your Node.js project by following this simple example:

const { gluesql } = require('gluesql');
const db = gluesql();

async function run() {
await db.query(`
CREATE TABLE User (id INTEGER, name TEXT);
CREATE TABLE Device (name TEXT, userId INTEGER);
INSERT INTO User VALUES (1, 'glue'), (2, 'sticky'), (3, 'watt');
INSERT INTO Device VALUES ('Phone', 1), ('Mic', 1), ('Monitor', 3), ('Mouse', 2), ('Touchpad', 2);
`);

const sql = `
SELECT
u.name as user,
d.name as device
FROM User u
JOIN Device d ON u.id = d.userId
`;
const [{ rows }] = await db.query(sql);
console.table(rows);
}

run();

This example demonstrates how to create tables, insert data, and perform a join query using GlueSQL in Node.js.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/getting-started/rust/index.html b/docs/0.16.0/getting-started/rust/index.html new file mode 100644 index 00000000..3e198230 --- /dev/null +++ b/docs/0.16.0/getting-started/rust/index.html @@ -0,0 +1,17 @@ + + + + + +Rust | GlueSQL + + + + + +
+

Rust

To install and use GlueSQL in your Rust project, you'll first need to add it as a dependency from crates.io. You can do this by adding the following lines to your Cargo.toml file:

[dependencies]
gluesql = "0.15"

By default, all available storage features are included with GlueSQL. Here's a list of the available features:

  • gluesql_sled_storage - Storage based on the persistent key-value database called sled
  • gluesql_memory_storage - Simple in-memory storage
  • gluesql-shared-memory-storage - A wrapper around memory-storage for easy use in multi-threaded environments
  • gluesql-json-storage - Storage that allows you to analyze and modify JSON or JSONL files using SQL
  • gluesql-composite-storage - A storage feature that enables joining and processing data from multiple storage types simultaneously
  • gluesql-web-storage - Storage supporting localStorage and sessionStorage, available only in web assembly builds
  • gluesql-idb-storage - IndexedDB-based storage, available only in web assembly builds

If you don't need all the default storage features, you can disable them and select only the ones you require. To do this, update your Cargo.toml file with the following lines:

[dependencies.gluesql]
version = "0.15"
default-features = false
features = ["gluesql_memory_storage", "gluesql-json-storage"]

This configuration will disable the default storage features and only include the gluesql_memory_storage and gluesql-json-storage features in your project.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/img/favicon.ico b/docs/0.16.0/img/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..70d988a846d5aee7032d48ab5ee8f7a7b6a05d00 GIT binary patch literal 15406 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

P;`Dc1@JN5_imJRsSlv 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�M+vz^JpG{rHH7GX>qqyOV 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 + Easy to Use + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/0.16.0/img/undraw_docusaurus_react.svg b/docs/0.16.0/img/undraw_docusaurus_react.svg new file mode 100644 index 00000000..94b5cf08 --- /dev/null +++ b/docs/0.16.0/img/undraw_docusaurus_react.svg @@ -0,0 +1,170 @@ + + Powered by React + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/0.16.0/img/undraw_docusaurus_tree.svg b/docs/0.16.0/img/undraw_docusaurus_tree.svg new file mode 100644 index 00000000..d9161d33 --- /dev/null +++ b/docs/0.16.0/img/undraw_docusaurus_tree.svg @@ -0,0 +1,40 @@ + + Focus on What Matters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/0.16.0/index.html b/docs/0.16.0/index.html new file mode 100644 index 00000000..991e99b5 --- /dev/null +++ b/docs/0.16.0/index.html @@ -0,0 +1,25 @@ + + + + + +Introduction | GlueSQL + + + + + +

+

Introduction

crates.io +npm +LICENSE +Rust +docs.rs +Chat +Coverage Status

Multi-Model Database Engine as a Library

GlueSQL is a Rust library for SQL databases that includes a parser (sqlparser-rs), an execution layer, and a variety of storage options, both persistent and non-persistent, all in one package. It is a versatile tool for developers, supporting both SQL and its own query builder (AST Builder). GlueSQL can handle structured and unstructured data, making it suitable for a wide range of use cases. It is portable and can be used with various storage types, including log files and read-write capable storage. GlueSQL is designed to be extensible and supports custom planners, making it a powerful tool for developers who need SQL support for their databases or services. GlueSQL is also flexible, as it can be used in Rust and JavaScript environments, and its language support is constantly expanding to include more programming languages.

"We offer a service where the GlueSQL team can implement and maintain your custom storage, especially beneficial for NoSQL databases with their own query planner and execution layer. We welcome any services wishing to support SQL and GlueSQL query interfaces. For more details, please refer to here."

If you're interested in learning more about GlueSQL, we recommend the following blog articles for a deeper dive into its capabilities and benefits:

  1. Breaking the Boundary between SQL and NoSQL Database
  2. Revolutionizing Databases by Unifying Query Interfaces
  3. Test-Driven Documentation - Automating User Manual Creation

Supporting SQL and AST Builder

GlueSQL supports both SQL and its own query builder (AST Builder). Unlike other ORMs, GlueSQL's AST Builder allows developers to build queries directly with GlueSQL's AST, enabling the use of all of GlueSQL's features. This is why we named it AST Builder instead of Query Builder.

SQL Example

SELECT id, name FROM Foo WHERE name = 'Lemon' AND price > 100

AST Builder Example

table("Foo")
.select()
// Filter by name using a SQL string
.filter("name = 'Lemon'")
// Filter by price using AST Builder methods
.filter(col("price").gt(100))
.project("id, name")
.execute(glue)
.await;

Supporting Structured and Unstructured Data with Schema Flexibility

GlueSQL supports both structured and unstructured (schemaless) data. While SQL databases typically assume that schemas are defined and used, GlueSQL does not make this assumption. It supports completely unstructured data, similar to a NoSQL document database, as well as semi-structured types such as MAP and LIST. This makes GlueSQL suitable for a wide range of use cases, including those that require handling of unstructured data. Additionally, it is possible to join tables with schemas and schemaless tables together and execute queries.

Schemaless SQL Example

CREATE TABLE Names (id INTEGER, name TEXT);
INSERT INTO Names VALUES (1, 'glue'), (2, 'sql');

CREATE TABLE Logs;
INSERT INTO Logs VALUES
('{ "id": 1, "value": 30 }'),
('{ "id": 2, "rate": 3.0, "list": [1, 2, 3] }'),
('{ "id": 3, "rate": 5.0, "value": 100 }');

SELECT * FROM Names JOIN Logs ON Names.id = Logs.id;
/*
| id | list | name | rate | value |
|----|---------|------|------|-------|
| 1 | | glue | | 30 |
| 2 |[1, 2, 3]| sql | 3 | |
*/

Supported Reference Storages

GlueSQL provides a variety of reference storages out of the box, including simple in-memory storage, key-value databases, log file-based storage like JSON & JSONL, and even Web Storage and IndexedDB supported by web browsers. These reference storages are readily available for use and can be easily adapted to a variety of storage systems. Additionally, GlueSQL is constantly expanding its list of supported storages, making it a versatile tool for developers.

Memory Storage

Memory Storage is a foundational storage option designed for in-memory, non-persistent data. It is a simple yet robust storage option that can be used in production environments.

Shared Memory Storage

Shared Memory Storage is a storage option designed to provide more comfortable usage of Memory Storage in concurrent environments. It wraps the Memory Storage with a read-write lock and an atomic reference count, allowing you to clone the storage instance and use it effortlessly across multiple threads. All storage instances will refer to the same data, making it a convenient option for concurrent environments.

Sled Storage

Sled Storage is a persistent data storage option for GlueSQL that is built on the Sled key-value embedded database in Rust. It is the only storage option currently supported by GlueSQL that implements all Store traits, from non-clustered indexes to transactions. Sled Storage is an excellent choice for handling and storing data in a Rust environment. To use Sled Storage, you can create a SledStorage instance using a path.

JSON Storage

With GlueSQL, you can use JSONL or JSON files as a database that supports SQL and AST Builder, making it a powerful option for developers who need to work with JSON data. JSON Storage is a storage system that uses two types of files: a schema file (optional) and a data file. The schema file is written in Standard SQL and stores the structure of the table, while the data file contains the actual data and supports two file formats: *.json and *.jsonl. JSON Storage supports all DML features, but is particularly specialized for SELECT and INSERT.

CSV Storage

CSV Storage in GlueSQL allows you to work with CSV files as if they were SQL databases. This feature is perfect for developers who want to use the simplicity of CSV files while taking advantage of SQL's capabilities.

Parquet Storage

Parquet Storage in GlueSQL allows you to treat Parquet files as SQL databases, enabling SQL operations like SELECT, INSERT, and UPDATE directly on Parquet data. It offers a convenient way to work with the efficiency and structure of Parquet files while utilizing the full power of SQL.

File Storage

File Storage is a custom storage implementation that utilizes the filesystem. +For each table name, the schema information is saved in a .sql format using a CREATE TABLE query. +The data is stored by creating a directory with the same name as the table and serializing the data using RON format in the subdirectory.

Git Storage

Git Storage is a custom storage option in GlueSQL that integrates seamlessly with a Git repository, allowing you to version-control your data directly within Git. This storage option automatically handles add and commit operations, ensuring your data changes are tracked. For remote operations like pull and push, GitStorage provides methods that developers can manually invoke, giving you full control over synchronization with remote repositories.

Mongo Storage

With Mongo storage, you can use mongodb as a storage for SQL queries. You can use all the features supported by GlueSQL, such as aggregations and joins, which were previously difficult to handle on an unstructured database. In particular, you can use GlueSQL's powerful schema system on mongodb, which is as strong as an RDBMS.

Web Storage

WebStorage, specifically localStorage and sessionStorage, can be used as a data storage system for GlueSQL. While WebStorage is a simple key-value database that uses string keys, GlueSQL makes it more powerful by adding support for SQL queries. This allows you to use SQL to interact with WebStorage, making it a convenient option for developers who are familiar with SQL. WebStorage can be used in JavaScript (Web) environments and Rust WebAssembly environments.

IndexedDB Storage

IndexedDB Storage is a powerful storage system that allows you to interact with IndexedDB using SQL. While using IndexedDB directly can be challenging, GlueSQL makes it easy to use by handling version management internally and storing data in JSON format. With GlueSQL, you can use SQL to interact with IndexedDB, making it a convenient option for developers who are familiar with SQL. You can use IndexedDB Storage in both JavaScript (Web) and Rust WebAssembly environments.

Composite Storage

Composite Storage is a powerful feature of GlueSQL that allows you to bundle together multiple existing storages, enabling you to perform JOIN operations across two distinct storages. This feature is utilized in various environments, including GlueSQL's JavaScript (Web) interface. Specifically, GlueSQL bundles together memory, localStorage, sessionStorage, and IndexedDB using Composite Storage in its JavaScript (Web) interface. This allows you to create tables using four different storages and perform operations like JOIN using SQL, all at once. Composite Storage is a versatile feature that can be used in many different scenarios, making it a valuable tool for developers who need to work with multiple storage systems, including those that require data migration between different storage systems.

Adapting GlueSQL to Your Environment: Creating Custom Storage

GlueSQL is designed to be adaptable to a wide variety of environments, including file systems, key-value databases, complex NoSQL databases, and remote APIs. To create a custom storage for GlueSQL, you only need to implement the Store and StoreMut traits provided by GlueSQL. These traits allow you to support SELECT queries and modify data, such as INSERT, UPDATE, and DELETE.

If you want to support additional features, such as schema changes, transactions, or custom functions, you can implement the corresponding traits. However, these traits are optional, and you can choose to implement only the ones that are relevant to your storage system.

To make it even easier to develop custom storages, GlueSQL provides a Test Suite that allows you to test your storage implementation against a set of standard SQL queries. This ensures that your storage system is compatible with GlueSQL and can handle common SQL operations.

Overall, creating a custom storage for GlueSQL is a straightforward process that allows you to adapt SQL and the AST Builder to your environment with ease.

GlueSQL Custom Storage: Let Us Handle It for You

Although anyone can develop a custom storage for GlueSQL with ease, our GlueSQL team can also implement and maintain it for you. This is especially recommended for NoSQL databases with their own query planner and execution layer, as adapting GlueSQL to them requires a deep understanding of GlueSQL's planner and storage layer details. We welcome not only database companies but also any services that want to support SQL and GlueSQL query interfaces. As GlueSQL is rapidly adding and improving features, we can help you develop and manage your custom storage effectively if you entrust it to us. If you're interested, please contact us at taehoon@gluesql.com.

Contribution

GlueSQL is a database project that is simpler than you might think. You only need to know three common Rust project commands: cargo fmt, cargo clippy, and cargo test. Don't hesitate to make pull requests and change the code as you see fit. We have set up GitHub Actions to validate your changes, so you don't have to worry about making mistakes. The line coverage of GlueSQL's core code is almost 99%, which is the result of not only careful test writing, but also of making the test suite easy to understand and use for anyone, even those who are not familiar with Rust. If you're not sure where to start, we recommend exploring the test suite first. Take a look at the existing features and try to understand how they work. Even if you're not familiar with Rust, you should be able to navigate the test suite without any problems. If there's a feature you'd like to see but isn't there yet, implementing it yourself and contributing it to GlueSQL is a great way to get involved. You can also check out the issues on the GlueSQL GitHub repository for more ideas on how to contribute.

License

This project is licensed under the Apache License, Version 2.0 - see the LICENSE file for details.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sitemap.xml b/docs/0.16.0/sitemap.xml new file mode 100644 index 00000000..8b5d07bf --- /dev/null +++ b/docs/0.16.0/sitemap.xml @@ -0,0 +1 @@ +https://gluesql.org/docs/0.16.0/blogweekly0.5https://gluesql.org/docs/0.16.0/blog/archiveweekly0.5https://gluesql.org/docs/0.16.0/blog/breaking-the-boundary-between-sql-and-nosqlweekly0.5https://gluesql.org/docs/0.16.0/blog/release-v0.14weekly0.5https://gluesql.org/docs/0.16.0/blog/release-v0.15weekly0.5https://gluesql.org/docs/0.16.0/blog/revolutionizing-databases-by-unifying-query-interfacesweekly0.5https://gluesql.org/docs/0.16.0/blog/tagsweekly0.5https://gluesql.org/docs/0.16.0/blog/tags/automationweekly0.5https://gluesql.org/docs/0.16.0/blog/tags/chat-gptweekly0.5https://gluesql.org/docs/0.16.0/blog/tags/databaseweekly0.5https://gluesql.org/docs/0.16.0/blog/tags/documentationweekly0.5https://gluesql.org/docs/0.16.0/blog/tags/gluesqlweekly0.5https://gluesql.org/docs/0.16.0/blog/tags/nosqlweekly0.5https://gluesql.org/docs/0.16.0/blog/tags/proposalweekly0.5https://gluesql.org/docs/0.16.0/blog/tags/query-interfaceweekly0.5https://gluesql.org/docs/0.16.0/blog/tags/release-noteweekly0.5https://gluesql.org/docs/0.16.0/blog/tags/sqlweekly0.5https://gluesql.org/docs/0.16.0/blog/tags/tddweekly0.5https://gluesql.org/docs/0.16.0/blog/tags/test-driven-documentationweekly0.5https://gluesql.org/docs/0.16.0/blog/tags/v-0-14weekly0.5https://gluesql.org/docs/0.16.0/blog/tags/v-0-15weekly0.5https://gluesql.org/docs/0.16.0/blog/test-driven-documentationweekly0.5https://gluesql.org/docs/0.16.0/weekly0.5https://gluesql.org/docs/0.16.0/ast-builder/expressions/conditionalweekly0.5https://gluesql.org/docs/0.16.0/ast-builder/expressions/nestedweekly0.5https://gluesql.org/docs/0.16.0/ast-builder/expressions/operator-basedweekly0.5https://gluesql.org/docs/0.16.0/ast-builder/expressions/pattern-matchingweekly0.5https://gluesql.org/docs/0.16.0/ast-builder/expressions/value-checkingweekly0.5https://gluesql.org/docs/0.16.0/ast-builder/functions/date-&-time/conversionweekly0.5https://gluesql.org/docs/0.16.0/ast-builder/functions/date-&-time/current-date-and-timeweekly0.5https://gluesql.org/docs/0.16.0/ast-builder/functions/date-&-time/date-and-time-extractionweekly0.5https://gluesql.org/docs/0.16.0/ast-builder/functions/date-&-time/formattingweekly0.5https://gluesql.org/docs/0.16.0/ast-builder/functions/geometry/coordinate-extractionweekly0.5https://gluesql.org/docs/0.16.0/ast-builder/functions/geometry/distance-calculationweekly0.5https://gluesql.org/docs/0.16.0/ast-builder/functions/geometry/point-creationweekly0.5https://gluesql.org/docs/0.16.0/ast-builder/functions/list-&-map/list-and-map-concatenationweekly0.5https://gluesql.org/docs/0.16.0/ast-builder/functions/list-&-map/list-manipulationweekly0.5https://gluesql.org/docs/0.16.0/ast-builder/functions/math/basic-arithmeticweekly0.5https://gluesql.org/docs/0.16.0/ast-builder/functions/math/conversionweekly0.5https://gluesql.org/docs/0.16.0/ast-builder/functions/math/logarithmic-and-exponentialweekly0.5https://gluesql.org/docs/0.16.0/ast-builder/functions/math/roundingweekly0.5https://gluesql.org/docs/0.16.0/ast-builder/functions/math/special-mathematicalweekly0.5https://gluesql.org/docs/0.16.0/ast-builder/functions/math/trigonometricweekly0.5https://gluesql.org/docs/0.16.0/ast-builder/functions/others/null-handlingweekly0.5https://gluesql.org/docs/0.16.0/ast-builder/functions/others/type-conversionweekly0.5https://gluesql.org/docs/0.16.0/ast-builder/functions/others/unique-identifierweekly0.5https://gluesql.org/docs/0.16.0/ast-builder/functions/text/case-conversionweekly0.5https://gluesql.org/docs/0.16.0/ast-builder/functions/text/character-conversionweekly0.5https://gluesql.org/docs/0.16.0/ast-builder/functions/text/paddingweekly0.5https://gluesql.org/docs/0.16.0/ast-builder/functions/text/position-and-indexingweekly0.5https://gluesql.org/docs/0.16.0/ast-builder/functions/text/text-manipulationweekly0.5https://gluesql.org/docs/0.16.0/ast-builder/functions/text/trimmingweekly0.5https://gluesql.org/docs/0.16.0/ast-builder/introweekly0.5https://gluesql.org/docs/0.16.0/ast-builder/statements/data-manipulation/deleting-dataweekly0.5https://gluesql.org/docs/0.16.0/ast-builder/statements/data-manipulation/inserting-dataweekly0.5https://gluesql.org/docs/0.16.0/ast-builder/statements/data-manipulation/updating-dataweekly0.5https://gluesql.org/docs/0.16.0/ast-builder/statements/querying/creating-derived-subqueriesweekly0.5https://gluesql.org/docs/0.16.0/ast-builder/statements/querying/data-aggregationweekly0.5https://gluesql.org/docs/0.16.0/ast-builder/statements/querying/data-injectionweekly0.5https://gluesql.org/docs/0.16.0/ast-builder/statements/querying/data-joiningweekly0.5https://gluesql.org/docs/0.16.0/ast-builder/statements/querying/data-selection-and-projectionweekly0.5https://gluesql.org/docs/0.16.0/ast-builder/statements/querying/data-sorting-and-limitingweekly0.5https://gluesql.org/docs/0.16.0/ast-builder/statements/querying/fetching-data-from-storageweekly0.5https://gluesql.org/docs/0.16.0/ast-builder/statements/querying/using-preloaded-dataweekly0.5https://gluesql.org/docs/0.16.0/getting-started/cliweekly0.5https://gluesql.org/docs/0.16.0/getting-started/javascript-webweekly0.5https://gluesql.org/docs/0.16.0/getting-started/nodejsweekly0.5https://gluesql.org/docs/0.16.0/getting-started/rustweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/data-types/booleanweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/data-types/byteaweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/data-types/dateweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/data-types/decimalweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/data-types/floatweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/data-types/inetweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/data-types/integersweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/data-types/intervalweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/data-types/listweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/data-types/mapweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/data-types/textweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/data-types/timeweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/data-types/timestampweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/data-types/uuidweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/datetime/extractweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/datetime/formatweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/datetime/nowweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/datetime/to-dateweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/datetime/to-timeweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/datetime/to-timestampweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/geometry/calc-distanceweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/geometry/get-xweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/geometry/get-yweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/geometry/pointweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/list-map/appendweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/list-map/concatweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/list-map/prependweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/list-map/sliceweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/list-map/spliceweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/math/absweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/math/acosweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/math/asinweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/math/atanweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/math/ceilweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/math/cosweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/math/degreesweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/math/divweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/math/expweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/math/floorweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/math/gcdweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/math/lcmweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/math/lnweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/math/logweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/math/log10weekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/math/log2weekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/math/modweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/math/piweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/math/powerweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/math/radiansweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/math/randweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/math/roundweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/math/signweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/math/sinweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/math/sqrtweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/math/tanweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/others/castweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/others/generate-uuidweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/others/ifnullweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/text/asciiweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/text/chrweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/text/concatweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/text/concat-wsweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/text/find-idxweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/text/initcapweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/text/leftweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/text/lowerweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/text/lpadweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/text/ltrimweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/text/positionweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/text/repeatweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/text/reverseweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/text/rightweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/text/rpadweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/text/rtrimweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/text/substrweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/text/trimweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/functions/text/upperweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/introweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/statements/data-definition/alter-tableweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/statements/data-definition/create-indexweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/statements/data-definition/create-tableweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/statements/data-definition/drop-indexweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/statements/data-definition/drop-tableweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/statements/data-manipulation/deleteweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/statements/data-manipulation/insertweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/statements/data-manipulation/updateweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/statements/metadata/data-dictionaryweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/statements/metadata/show-tablesweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/statements/querying/aggregationweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/statements/querying/joinweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/statements/querying/limitweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/statements/querying/schemalessweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/statements/querying/whereweekly0.5https://gluesql.org/docs/0.16.0/sql-syntax/statements/transactionweekly0.5https://gluesql.org/docs/0.16.0/storages/developing-custom-storages/introweekly0.5https://gluesql.org/docs/0.16.0/storages/developing-custom-storages/store-traits/alter-tableweekly0.5https://gluesql.org/docs/0.16.0/storages/developing-custom-storages/store-traits/custom-functionweekly0.5https://gluesql.org/docs/0.16.0/storages/developing-custom-storages/store-traits/custom-function-mutweekly0.5https://gluesql.org/docs/0.16.0/storages/developing-custom-storages/store-traits/index-mutweekly0.5https://gluesql.org/docs/0.16.0/storages/developing-custom-storages/store-traits/index-traitweekly0.5https://gluesql.org/docs/0.16.0/storages/developing-custom-storages/store-traits/metadataweekly0.5https://gluesql.org/docs/0.16.0/storages/developing-custom-storages/store-traits/storeweekly0.5https://gluesql.org/docs/0.16.0/storages/developing-custom-storages/store-traits/store-mutweekly0.5https://gluesql.org/docs/0.16.0/storages/developing-custom-storages/store-traits/transactionweekly0.5https://gluesql.org/docs/0.16.0/storages/developing-custom-storages/using-test-suiteweekly0.5https://gluesql.org/docs/0.16.0/storages/introweekly0.5https://gluesql.org/docs/0.16.0/storages/supported-storages/composite-storageweekly0.5https://gluesql.org/docs/0.16.0/storages/supported-storages/csv-storageweekly0.5https://gluesql.org/docs/0.16.0/storages/supported-storages/idb-storageweekly0.5https://gluesql.org/docs/0.16.0/storages/supported-storages/json-storageweekly0.5https://gluesql.org/docs/0.16.0/storages/supported-storages/memory-storageweekly0.5https://gluesql.org/docs/0.16.0/storages/supported-storages/parquet-storageweekly0.5https://gluesql.org/docs/0.16.0/storages/supported-storages/shared-memory-storageweekly0.5https://gluesql.org/docs/0.16.0/storages/supported-storages/sled-storageweekly0.5https://gluesql.org/docs/0.16.0/storages/supported-storages/web-storageweekly0.5 \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/data-types/boolean/index.html b/docs/0.16.0/sql-syntax/data-types/boolean/index.html new file mode 100644 index 00000000..285f6d80 --- /dev/null +++ b/docs/0.16.0/sql-syntax/data-types/boolean/index.html @@ -0,0 +1,17 @@ + + + + + +BOOLEAN | GlueSQL + + + + + +
+

BOOLEAN

The BOOLEAN data type in SQL is used to store boolean values, which can be either TRUE or FALSE. This data type is useful for representing binary states or conditions in your data.

Here's an example of how to create a table, insert data, and query data using the BOOLEAN data type:

Creating a table with a BOOLEAN column

To create a table with a BOOLEAN column, use the following SQL syntax:

CREATE TABLE user_active (username TEXT, is_active BOOLEAN);

Inserting data into the BOOLEAN column

To insert data into the BOOLEAN column, provide the boolean values as TRUE or FALSE:

INSERT INTO user_active (username, is_active) VALUES
('user1', TRUE),
('user2', FALSE),
('user3', TRUE);

Querying data from the BOOLEAN column

To query data from the BOOLEAN column, use standard SQL syntax:

SELECT username, is_active FROM user_active;

This query will return the following result:

username | is_active
---------|----------
user1 | TRUE
user2 | FALSE
user3 | TRUE

Casting between BOOLEAN and INTEGER

You can cast between BOOLEAN and INTEGER values:

  • When casting a BOOLEAN to an INTEGER, TRUE becomes 1 and FALSE becomes 0.
  • When casting an INTEGER to a BOOLEAN, 1 becomes TRUE and 0 becomes FALSE. Other integer values will result in an error.

Example:

SELECT CAST(1 AS BOOLEAN); -- Result: TRUE
SELECT CAST(0 AS BOOLEAN); -- Result: FALSE
SELECT CAST(TRUE AS INTEGER); -- Result: 1
SELECT CAST(FALSE AS INTEGER); -- Result: 0

Note that casting negative integers or integers greater than 1 to BOOLEAN will result in an error.

Conclusion

In summary, the BOOLEAN data type is a simple yet powerful way to represent binary states in SQL databases. With its ability to store TRUE and FALSE values, it can be used in various applications where binary conditions are necessary. Additionally, its compatibility with casting to and from INTEGER values provides added flexibility in data manipulation and querying. By understanding the basics of the BOOLEAN data type and its use cases, you can effectively use it in your database designs and operations.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/data-types/bytea/index.html b/docs/0.16.0/sql-syntax/data-types/bytea/index.html new file mode 100644 index 00000000..c502ef68 --- /dev/null +++ b/docs/0.16.0/sql-syntax/data-types/bytea/index.html @@ -0,0 +1,17 @@ + + + + + +BYTEA | GlueSQL + + + + + +
+

BYTEA

The BYTEA data type in SQL is used to store binary data, such as images, audio files, or any other type of data that needs to be stored in its raw form. In GlueSQL, the BYTEA data type is represented as a sequence of bytes.

Here's an example of how to create a table, insert data, and query data using the BYTEA data type:

Creating a table with a BYTEA column

To create a table with a BYTEA column, use the following SQL syntax:

CREATE TABLE binary_data (data BYTEA);

Inserting data into the BYTEA column

To insert data into the BYTEA column, provide the binary data in hexadecimal format using the X prefix:

INSERT INTO binary_data (data) VALUES
(X'123456'),
(X'ab0123'),
(X'936DA0');

Please note that the hexadecimal string must have an even number of characters, or an error will be thrown.

Querying data from the BYTEA column

To query data from the BYTEA column, use standard SQL syntax:

SELECT data FROM binary_data;

This query will return the following result:

data
----------------
123456
ab0123
936DA0

Error handling

When inserting data into the BYTEA column, you may encounter errors due to incompatible data types or incorrectly formatted hexadecimal strings. For example, inserting a regular integer or an odd-length hexadecimal string will result in an error:

INSERT INTO binary_data (data) VALUES (0);
-- Error: Incompatible literal for data type BYTEA

INSERT INTO binary_data (data) VALUES (X'123');
-- Error: Failed to decode hexadecimal string

Conclusion

The BYTEA data type is essential for storing binary data in SQL databases. By understanding the basics of the BYTEA data type and its use cases, you can effectively use it in your database designs and operations, ensuring that your applications can manage binary data efficiently and securely.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/data-types/date/index.html b/docs/0.16.0/sql-syntax/data-types/date/index.html new file mode 100644 index 00000000..61d0ece9 --- /dev/null +++ b/docs/0.16.0/sql-syntax/data-types/date/index.html @@ -0,0 +1,17 @@ + + + + + +DATE | GlueSQL + + + + + +
+

DATE

In GlueSQL, the DATE data type is used to store date values in the format 'YYYY-MM-DD'. Note that GlueSQL currently does not support timezones.

Creating a table with DATE columns

To create a table with columns of type DATE, use the CREATE TABLE statement:

CREATE TABLE DateLog (
id INTEGER,
date1 DATE,
date2 DATE
);

Inserting data into a table with DATE columns

To insert data into a table with DATE columns, use the INSERT INTO statement:

INSERT INTO DateLog VALUES
(1, '2020-06-11', '2021-03-01'),
(2, '2020-09-30', '1989-01-01'),
(3, '2021-05-01', '2021-05-01');

Querying data from a table with DATE columns

To query data from a table with DATE columns, use the SELECT statement:

SELECT id, date1, date2 FROM DateLog;

Filtering data using DATE columns

You can use various comparison operators like >, <, <=, >=, and = to filter data based on DATE columns:

SELECT * FROM DateLog WHERE date1 > date2;

SELECT * FROM DateLog WHERE date1 <= date2;

SELECT * FROM DateLog WHERE date1 = DATE '2020-06-11';

SELECT * FROM DateLog WHERE date2 < '2000-01-01';

SELECT * FROM DateLog WHERE '1999-01-03' < DATE '2000-01-01';

Performing date arithmetic

You can perform arithmetic operations on DATE columns using INTERVAL and various date arithmetic operators:

SELECT
id,
date1 - date2 AS date_sub,
date1 - INTERVAL '1' DAY AS sub,
date2 + INTERVAL '1' MONTH AS add
FROM DateLog;

Handling invalid date values

If you try to insert an invalid date value into a DATE column, GlueSQL will return an error:

INSERT INTO DateLog VALUES (1, '12345-678', '2021-05-01');

This will result in an error similar to the following:

failed to parse date 12345-678

Conclusion

In summary, the DATE data type in GlueSQL allows you to store and manipulate date values in your database. You can create tables with DATE columns, insert and query data, filter data based on date comparisons, and perform date arithmetic using various operators and intervals. Always remember to use valid date formats when inserting data into DATE columns to avoid errors.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/data-types/decimal/index.html b/docs/0.16.0/sql-syntax/data-types/decimal/index.html new file mode 100644 index 00000000..3435196e --- /dev/null +++ b/docs/0.16.0/sql-syntax/data-types/decimal/index.html @@ -0,0 +1,17 @@ + + + + + +DECIMAL | GlueSQL + + + + + +
+

DECIMAL

The DECIMAL data type in SQL is used to store exact numeric values, making it suitable for financial calculations and other operations requiring a high level of precision without round-off errors. In GlueSQL, the DECIMAL data type is implemented using a pure Rust library, providing a 96-bit integer number, a scaling factor for specifying the decimal fraction, and a 1-bit sign.

Here's an example of how to create a table, insert data, and query data using the DECIMAL data type:

Creating a table with a DECIMAL column

To create a table with a DECIMAL column, use the following SQL syntax:

CREATE TABLE financial_data (description TEXT, value DECIMAL);

Inserting data into the DECIMAL column

To insert data into the DECIMAL column, provide the exact numeric values:

INSERT INTO financial_data (description, value) VALUES
('Revenue', 15000.25),
('Expense', 12000.75),
('Profit', 2999.50);

Querying data from the DECIMAL column

To query data from the DECIMAL column, use standard SQL syntax:

SELECT description, value FROM financial_data;

This query will return the following result:

description | value
------------|---------
Revenue | 15000.25
Expense | 12000.75
Profit | 2999.50

Truncating trailing zeros

In GlueSQL's DECIMAL implementation, trailing zeros are preserved in the binary representation and may be exposed when converting the value to a string. To truncate trailing zeros, you can use the normalize or round_dp functions in Rust.

Conclusion

The DECIMAL data type is crucial for handling precise numeric values in SQL databases, especially in financial calculations and other applications requiring high accuracy without round-off errors. By understanding the basics of the DECIMAL data type and its use cases, you can effectively use it in your database designs and operations, ensuring that your applications can manage exact numeric values with precision.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/data-types/float/index.html b/docs/0.16.0/sql-syntax/data-types/float/index.html new file mode 100644 index 00000000..9de68e3a --- /dev/null +++ b/docs/0.16.0/sql-syntax/data-types/float/index.html @@ -0,0 +1,17 @@ + + + + + +FLOAT | GlueSQL + + + + + +
+

FLOAT

The FLOAT data type in SQL is used to store floating-point numbers. In GlueSQL, the FLOAT data type represents a 64-bit floating-point number, providing the ability to store numbers with decimal values and a wide range of magnitude.

Here's an example of how to create a table, insert data, and query data using the FLOAT data type:

Creating a table with a FLOAT column

To create a table with a FLOAT column, use the following SQL syntax:

CREATE TABLE product_prices (product_name TEXT, price FLOAT);

Inserting data into the FLOAT column

To insert data into the FLOAT column, provide the floating-point values:

INSERT INTO product_prices (product_name, price) VALUES
('Product A', 19.99),
('Product B', 39.49),
('Product C', 12.75);

Querying data from the FLOAT column

To query data from the FLOAT column, use standard SQL syntax:

SELECT product_name, price FROM product_prices;

This query will return the following result:

product_name | price
-------------|-------
Product A | 19.99
Product B | 39.49
Product C | 12.75

Conclusion

The FLOAT data type is essential for handling numeric data with decimal values and various magnitudes. By understanding the basics of the FLOAT data type and its use cases, you can effectively use it in your database designs and operations, ensuring that your applications can handle a wide range of numerical values with precision.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/data-types/inet/index.html b/docs/0.16.0/sql-syntax/data-types/inet/index.html new file mode 100644 index 00000000..51aa1ce3 --- /dev/null +++ b/docs/0.16.0/sql-syntax/data-types/inet/index.html @@ -0,0 +1,17 @@ + + + + + +INET | GlueSQL + + + + + +
+

INET

The INET data type in SQL is used to store IPv4 and IPv6 addresses. These addresses can be compared, filtered, and sorted using standard SQL operations.

Here's an example of how to create a table, insert data, and query data using the INET data type:

Creating a table with an INET column

To create a table with an INET column, use the following SQL syntax:

CREATE TABLE computer (ip INET);

Inserting data into the INET column

To insert data into the INET column, provide the IP addresses as strings or integers:

INSERT INTO computer VALUES
('::1'),
('127.0.0.1'),
('0.0.0.0'),
(4294967295),
(9876543210);

Querying data from the INET column

To query data from the INET column, use standard SQL syntax:

SELECT * FROM computer;

This query will return the following result:

ip
-----------------
::1
127.0.0.1
0.0.0.0
255.255.255.255
::2:4cb0:16ea

Filtering data using the INET column

You can filter data using the INET column with standard SQL operators:

SELECT * FROM computer WHERE ip > '127.0.0.1';

This query will return the following result:

ip
-----------------
::1
255.255.255.255
::2:4cb0:16ea

Querying for specific IP addresses

To query for specific IP addresses, use the following syntax:

SELECT * FROM computer WHERE ip = '127.0.0.1';

This query will return the following result:

ip
---------
127.0.0.1
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/data-types/integers/index.html b/docs/0.16.0/sql-syntax/data-types/integers/index.html new file mode 100644 index 00000000..b4713a36 --- /dev/null +++ b/docs/0.16.0/sql-syntax/data-types/integers/index.html @@ -0,0 +1,17 @@ + + + + + +Integer Types | GlueSQL + + + + + +
+

Integer Types

GlueSQL supports the following integer data types:

  • INT8: 8-bit signed integer
  • INT16: 16-bit signed integer
  • INT32: 32-bit signed integer
  • INT or INTEGER: 64-bit signed integer (default)
  • INT128: 128-bit signed integer
  • UINT8: 8-bit unsigned integer
  • UINT16: 16-bit unsigned integer
  • UINT32: 32-bit unsigned integer
  • UINT64: 64-bit unsigned integer
  • UINT128: 128-bit unsigned integer

For general purposes, you can use INTEGER to specify a 64-bit signed integer.

Here's an example of how to create a table with integer data types:

CREATE TABLE Item (
field_one INTEGER,
field_two INTEGER
);

You can insert data into the Item table as follows:

INSERT INTO Item VALUES (1, -1), (-2, 2), (3, 3), (-4, -4);

You can perform arithmetic operations such as addition, subtraction, multiplication, division, and modulo on integer columns. Note that if you perform arithmetic operations on columns with different integer types, GlueSQL will automatically convert the types of the operands to match the type of the left-hand operand. For example, if you perform UINT8 + INT64, GlueSQL will convert the INT64 operand to UINT8 and then perform the addition.

Integer types are an important part of SQL, and you can use them to store data ranging from small whole numbers to large integers. By understanding how to use integer types in your database, you can write efficient and effective SQL queries that work with a wide range of data.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/data-types/interval/index.html b/docs/0.16.0/sql-syntax/data-types/interval/index.html new file mode 100644 index 00000000..870bd1eb --- /dev/null +++ b/docs/0.16.0/sql-syntax/data-types/interval/index.html @@ -0,0 +1,17 @@ + + + + + +INTERVAL | GlueSQL + + + + + +
+

INTERVAL

The INTERVAL data type in GlueSQL is used to represent a period of time. In accordance with the ANSI SQL standard, several subtypes of INTERVAL can be used to represent different units of time, such as years, months, days, hours, minutes, and seconds. These subtypes are:

  • YEAR
  • YEAR TO MONTH
  • MONTH
  • DAY
  • DAY TO HOUR
  • DAY TO MINUTE
  • DAY TO SECOND
  • HOUR
  • HOUR TO MINUTE
  • HOUR TO SECOND
  • MINUTE
  • MINUTE TO SECOND
  • SECOND

Creating a Table with INTERVAL Columns

To create a table with INTERVAL columns, simply use the INTERVAL keyword for the data type:

CREATE TABLE IntervalLog (
id INTEGER,
interval1 INTERVAL,
interval2 INTERVAL
);

Inserting INTERVAL Values

To insert INTERVAL values into a table, use the INTERVAL keyword followed by a string literal representing the interval value:

INSERT INTO IntervalLog VALUES
(1, INTERVAL '1-2' YEAR TO MONTH, INTERVAL 30 MONTH),
(2, INTERVAL 12 DAY, INTERVAL '35' HOUR),
(3, INTERVAL '12' MINUTE, INTERVAL 300 SECOND),
(4, INTERVAL '-3 14' DAY TO HOUR, INTERVAL '3 12:30' DAY TO MINUTE),
(5, INTERVAL '3 14:00:00' DAY TO SECOND, INTERVAL '3 12:30:12.1324' DAY TO SECOND),
(6, INTERVAL '12:00' HOUR TO MINUTE, INTERVAL '-12:30:12' HOUR TO SECOND),
(7, INTERVAL '-1000-11' YEAR TO MONTH, INTERVAL '-30:11' MINUTE TO SECOND);

INTERVAL Subtypes and Syntax

Here are some examples of how to use different INTERVAL subtypes:

  • YEAR: INTERVAL '5' YEAR
  • YEAR TO MONTH: INTERVAL '5-3' YEAR TO MONTH
  • MONTH: INTERVAL '6' MONTH
  • DAY: INTERVAL '7' DAY
  • DAY TO HOUR: INTERVAL '2 12' DAY TO HOUR
  • DAY TO MINUTE: INTERVAL '2 12:30' DAY TO MINUTE
  • DAY TO SECOND: INTERVAL '2 12:30:45' DAY TO SECOND
  • HOUR: INTERVAL '18' HOUR
  • HOUR TO MINUTE: INTERVAL '18:30' HOUR TO MINUTE
  • HOUR TO SECOND: INTERVAL '18:30:45' HOUR TO SECOND
  • MINUTE: INTERVAL '45' MINUTE
  • MINUTE TO SECOND: INTERVAL '45:30' MINUTE TO SECOND
  • SECOND: INTERVAL '30' SECOND

Unsupported Conversions

In GlueSQL, you cannot convert between different INTERVAL subtypes, such as converting 1 MONTH to DAYS or converting YEAR TO MONTH to DAY TO SECOND. These conversions are not supported.

Conclusion

The INTERVAL data type is a powerful way to represent time periods in GlueSQL. By following the ANSI SQL standard, you can use a combination of subtypes to represent complex periods of time. Use the INTERVAL keyword when creating tables and inserting values to make the most of this data type.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/data-types/list/index.html b/docs/0.16.0/sql-syntax/data-types/list/index.html new file mode 100644 index 00000000..a9787892 --- /dev/null +++ b/docs/0.16.0/sql-syntax/data-types/list/index.html @@ -0,0 +1,17 @@ + + + + + +LIST | GlueSQL + + + + + +
+

LIST

The LIST data type in GlueSQL is used to store ordered collections of elements, similar to JSON arrays. The elements can be any valid data supported by GlueSQL, such as numbers, strings, booleans, null, MAP, or even other nested LIST values. Although the input is provided in a JSON array format for convenience, it can store more than just JSON data.

Here is an example of creating a table with a LIST data type:

CREATE TABLE ListType (
id INTEGER,
items LIST
);

You can insert data into the table using JSON-like syntax:

INSERT INTO ListType VALUES
(1, '[1, 2, 3]'),
(2, '["hello", "world", 30, true, [9,8]]'),
(3, '[{ "foo": 100, "bar": [true, 0, [10.5, false] ] }, 10, 20]');

To access the elements in a LIST, you can use the index operator []:

SELECT id, items[1] AS second FROM ListType;

This query would return the following result:

 id | second
----|--------
1 | 2
2 | world
3 | 10

You can also access nested elements using the index operator, like this:

SELECT id, items[3][0] AS hundred FROM ListType2;

This query would return the following result:

 id | hundred
----|--------
1 | null
2 | 100
3 | null

If a specified index is out of range or the element is not a MAP or LIST, the result will be null.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/data-types/map/index.html b/docs/0.16.0/sql-syntax/data-types/map/index.html new file mode 100644 index 00000000..9b80dca4 --- /dev/null +++ b/docs/0.16.0/sql-syntax/data-types/map/index.html @@ -0,0 +1,17 @@ + + + + + +MAP | GlueSQL + + + + + +
+

MAP

The MAP data type in GlueSQL is used to store nested key-value pairs, similar to JSON objects. The object keys must be strings, and the values can be any valid data supported by GlueSQL, such as numbers, strings, booleans, null, or even other nested MAP values. Although the input is provided in a JSON object format for convenience, it can store more than just JSON data.

Here is an example of creating a table with a MAP data type:

CREATE TABLE MapType (
id INTEGER,
nested MAP
);

You can insert data into the table using JSON-like syntax:

INSERT INTO MapType VALUES
(1, '{"a": true, "b": 2}'),
(2, '{"a": {"foo": "ok", "b": "steak"}, "b": 30}'),
(3, '{"a": {"b": {"c": {"d": 10}}}}');

To access the nested values in a MAP, you can use the index operator []:

SELECT id, nested['a']['foo'] AS foo FROM MapType;

This query would return the following result:

 id | foo
----|-----
1 | null
2 | ok
3 | null

You can also perform arithmetic operations on nested values, like this:

SELECT id, nested['a']['b']['c']['d'] * 2 AS good2 FROM MapType;

This query would return the following result:

 id | good2
----|------
1 | null
2 | null
3 | 20

If a specified key does not exist in the MAP, the result will be null.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/data-types/text/index.html b/docs/0.16.0/sql-syntax/data-types/text/index.html new file mode 100644 index 00000000..f8156ac2 --- /dev/null +++ b/docs/0.16.0/sql-syntax/data-types/text/index.html @@ -0,0 +1,17 @@ + + + + + +TEXT | GlueSQL + + + + + +
+

TEXT

The TEXT data type in SQL is used to store variable-length character strings. In GlueSQL, the TEXT data type is the only supported string data type, providing the ability to store and manage strings of varying lengths.

Here's an example of how to create a table, insert data, and query data using the TEXT data type:

Creating a table with a TEXT column

To create a table with a TEXT column, use the following SQL syntax:

CREATE TABLE users (username TEXT, email TEXT);

Inserting data into the TEXT column

To insert data into the TEXT column, provide the string values:

INSERT INTO users (username, email) VALUES
('user1', 'user1@example.com'),
('user2', 'user2@example.com'),
('user3', 'user3@example.com');

Querying data from the TEXT column

To query data from the TEXT column, use standard SQL syntax:

SELECT username, email FROM users;

This query will return the following result:

username | email
---------|-------------------
user1 | user1@example.com
user2 | user2@example.com
user3 | user3@example.com

Conclusion

The TEXT data type is a versatile and essential data type for handling and storing character strings in SQL databases. By understanding the basics of the TEXT data type and its use cases, you can effectively use it in your database designs and operations, ensuring that your applications can manage a wide range of textual data with ease.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/data-types/time/index.html b/docs/0.16.0/sql-syntax/data-types/time/index.html new file mode 100644 index 00000000..338d20c7 --- /dev/null +++ b/docs/0.16.0/sql-syntax/data-types/time/index.html @@ -0,0 +1,17 @@ + + + + + +TIME | GlueSQL + + + + + +
+

TIME

In GlueSQL, the TIME data type is used to store time values in the format 'HH:MM:SS.SSS'. The code snippet provided demonstrates how to create a table with TIME columns, insert data into it, and perform various queries and operations on the data.

Creating a table with TIME columns

To create a table with columns of type TIME, use the CREATE TABLE statement:

CREATE TABLE TimeLog (
id INTEGER,
time1 TIME,
time2 TIME
);

Inserting data into a table with TIME columns

To insert data into a table with TIME columns, use the INSERT INTO statement:

INSERT INTO TimeLog VALUES
(1, '12:30:00', '13:31:01.123'),
(2, '9:2:1', 'AM 08:02:01.001'),
(3, 'PM 2:59', '9:00:00 AM');

Querying data from a table with TIME columns

To query data from a table with TIME columns, use the SELECT statement:

SELECT id, time1, time2 FROM TimeLog;

Filtering data using TIME columns

You can use various comparison operators like >, <, <=, >=, and = to filter data based on TIME columns:

SELECT * FROM TimeLog WHERE time1 > time2;

SELECT * FROM TimeLog WHERE time1 <= time2;

SELECT * FROM TimeLog WHERE time1 = TIME '14:59:00';

SELECT * FROM TimeLog WHERE time1 < '1:00 PM';

Performing time arithmetic

You can perform arithmetic operations on TIME columns using INTERVAL:

SELECT
id,
time1 - time2 AS time_sub,
time1 + INTERVAL '1' HOUR AS add,
time2 - INTERVAL '250' MINUTE AS sub
FROM TimeLog;

You can also add a TIME column to a DATE value to get a TIMESTAMP result:

SELECT
id,
DATE '2021-01-05' + time2 AS timestamp
FROM TimeLog LIMIT 1;

Handling invalid time values

If you try to insert an invalid time value into a TIME column, GlueSQL will return an error:

INSERT INTO TimeLog VALUES (1, '12345-678', '20:05:01');

This will result in an error similar to the following:

failed to parse time 12345-678

Conclusion

In GlueSQL, the TIME data type is used to store time values in the format 'HH:MM:SS.SSS'. The provided code snippet demonstrates how to create a table with TIME columns, insert data into it, and perform various queries and operations on the data. GlueSQL supports arithmetic operations on TIME columns using INTERVAL, and you can also add a TIME column to a DATE value to get a TIMESTAMP result. Keep in mind that inserting invalid time values into a TIME column will result in an error.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/data-types/timestamp/index.html b/docs/0.16.0/sql-syntax/data-types/timestamp/index.html new file mode 100644 index 00000000..107d5933 --- /dev/null +++ b/docs/0.16.0/sql-syntax/data-types/timestamp/index.html @@ -0,0 +1,17 @@ + + + + + +TIMESTAMP | GlueSQL + + + + + +
+

TIMESTAMP

In GlueSQL, the TIMESTAMP data type is used to store date and time values in the format 'YYYY-MM-DD HH:MM:SS.SSSS'. Although timezone information can be included in the input string, GlueSQL stores all TIMESTAMP values in UTC, discarding the timezone information.

Creating a table with TIMESTAMP columns

To create a table with columns of type TIMESTAMP, use the CREATE TABLE statement:

CREATE TABLE TimestampLog (
id INTEGER,
t1 TIMESTAMP,
t2 TIMESTAMP
);

Inserting data into a table with TIMESTAMP columns

To insert data into a table with TIMESTAMP columns, use the INSERT INTO statement:

INSERT INTO TimestampLog VALUES
(1, '2020-06-11 11:23:11Z', '2021-03-01'),
(2, '2020-09-30 12:00:00 -07:00', '1989-01-01T00:01:00+09:00'),
(3, '2021-04-30T07:00:00.1234-17:00', '2021-05-01T09:00:00.1234+09:00');

The input strings include timezone information, but GlueSQL will convert and store them as UTC timestamps.

Querying data from a table with TIMESTAMP columns

To query data from a table with TIMESTAMP columns, use the SELECT statement:

SELECT id, t1, t2 FROM TimestampLog;

Filtering data using TIMESTAMP columns

You can use various comparison operators like >, <, <=, >=, and = to filter data based on TIMESTAMP columns:

SELECT * FROM TimestampLog WHERE t1 > t2;

SELECT * FROM TimestampLog WHERE t1 = t2;

SELECT * FROM TimestampLog WHERE t1 = '2020-06-11T14:23:11+0300';

SELECT * FROM TimestampLog WHERE t2 < TIMESTAMP '2000-01-01';

Performing timestamp arithmetic

You can perform arithmetic operations on TIMESTAMP columns using INTERVAL:

SELECT id, t1 - t2 AS timestamp_sub FROM TimestampLog;

SELECT
id,
t1 - INTERVAL '1' DAY AS sub,
t2 + INTERVAL '1' MONTH AS add
FROM TimestampLog;

Handling invalid timestamp values

If you try to insert an invalid timestamp value into a TIMESTAMP column, GlueSQL will return an error:

INSERT INTO TimestampLog VALUES (1, '12345-678', '2021-05-01');

This will result in an error similar to the following:

failed to parse timestamp: 12345-678

Conclusion

In GlueSQL, the TIMESTAMP data type allows you to store date and time values with precision up to milliseconds. The provided code snippet demonstrates how to create a table with TIMESTAMP columns, insert data into it, and perform various queries and operations on the data. When inserting a TIMESTAMP value, the timezone information is removed, and the data is stored in UTC. This ensures that all time values are consistent and can be easily converted to different time zones when needed.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/data-types/uuid/index.html b/docs/0.16.0/sql-syntax/data-types/uuid/index.html new file mode 100644 index 00000000..f5a1e9f3 --- /dev/null +++ b/docs/0.16.0/sql-syntax/data-types/uuid/index.html @@ -0,0 +1,17 @@ + + + + + +UUID | GlueSQL + + + + + +
+

UUID

The UUID data type in SQL is used to store universally unique identifiers (UUIDs). These identifiers can be compared, filtered, and sorted using standard SQL operations.

Here's an example of how to create a table, insert data, and query data using the UUID data type:

Creating a table with a UUID column

To create a table with a UUID column, use the following SQL syntax:

CREATE TABLE UUID (uuid_field UUID);

Inserting data into the UUID column

To insert data into the UUID column, provide the UUIDs as strings or in the format X'<hexadecimal_value>'. You can also use the urn:uuid: prefix. Note that providing a UUID as a plain number is not supported and will result in an error.

INSERT INTO UUID VALUES
(X'936DA01F9ABD4d9d80C702AF85C822A8'),
('550e8400-e29b-41d4-a716-446655440000'),
('urn:uuid:F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4');

Generating a random UUID

To generate a random UUID (version 4), use the GENERATE_UUID function:

INSERT INTO UUID (uuid_field) VALUES (GENERATE_UUID());

Querying data from the UUID column

To query data from the UUID column, use standard SQL syntax:

SELECT uuid_field FROM UUID;

This query will return the following result:

uuid_field
------------------------------------
936DA01F-9ABD-4D9D-80C7-02AF85C822A8
550E8400-E29B-41D4-A716-446655440000
F9168C5E-CEB2-4FAA-B6BF-329BF39FA1E4

Filtering and manipulating data using the UUID column

You can filter, update, and delete data using the UUID column with standard SQL operations:

-- Filtering
SELECT uuid_field FROM UUID WHERE uuid_field = '550e8400-e29b-41d4-a716-446655440000';

-- Updating
UPDATE UUID SET uuid_field = 'urn:uuid:F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4' WHERE uuid_field = '550e8400-e29b-41d4-a716-446655440000';

-- Deleting
DELETE FROM UUID WHERE uuid_field = '550e8400-e29b-41d4-a716-446655440000';
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/datetime/extract/index.html b/docs/0.16.0/sql-syntax/functions/datetime/extract/index.html new file mode 100644 index 00000000..98f9e476 --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/datetime/extract/index.html @@ -0,0 +1,17 @@ + + + + + +EXTRACT | GlueSQL + + + + + +
+

EXTRACT

The EXTRACT function in SQL is used to retrieve a specific datetime field from a date, time, or interval.

Syntax

EXTRACT(field FROM source)
  • field: The datetime field to extract. Valid fields include YEAR, MONTH, DAY, HOUR, MINUTE, SECOND.
  • source: The date, time, or interval value from which the datetime field is to be extracted.

Usage

Here are examples of how EXTRACT can be used to pull specific datetime components from various types of datetime and interval data.

  1. Extracting the HOUR from a TIMESTAMP:

    SELECT EXTRACT(HOUR FROM TIMESTAMP '2016-12-31 13:30:15') as extract;

    This returns 13.

  2. Extracting the YEAR from a TIMESTAMP:

    SELECT EXTRACT(YEAR FROM TIMESTAMP '2016-12-31 13:30:15') as extract;

    This returns 2016.

  3. Extracting the SECOND from a TIME value:

    SELECT EXTRACT(SECOND FROM TIME '17:12:28') as extract;

    This returns 28.

  4. Extracting the DAY from a DATE value:

    SELECT EXTRACT(DAY FROM DATE '2021-10-06') as extract;

    This returns 6.

  5. Extracting from INTERVAL data:

    SELECT EXTRACT(YEAR FROM INTERVAL '3' YEAR) as extract;
    SELECT EXTRACT(MINUTE FROM INTERVAL '7' MINUTE) as extract;

    These return 3 and 7, respectively.

Note that the EXTRACT function expects the source to be of a compatible datetime or interval type. Using a value of an incompatible type, such as a number or a string that cannot be interpreted as a datetime, will result in an error.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/datetime/format/index.html b/docs/0.16.0/sql-syntax/functions/datetime/format/index.html new file mode 100644 index 00000000..7f85e1c7 --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/datetime/format/index.html @@ -0,0 +1,17 @@ + + + + + +FORMAT | GlueSQL + + + + + +
+

FORMAT

The FORMAT function in SQL is used to format date, time, and timestamp values into a specified format.

Syntax

FORMAT(value, format)
  • value: The date, time, or timestamp value that is to be formatted.
  • format: The format in which the value is to be displayed. This is a string that contains format specifiers, such as %Y for four-digit year, %m for two-digit month, and so on.

Usage

Here are examples of how FORMAT can be used to display datetime components in various formats:

  1. Formatting a DATE value:

    SELECT FORMAT(DATE '2017-06-15','%Y-%m') AS date;

    This returns "2017-06".

  2. Formatting a TIMESTAMP value:

    SELECT FORMAT(TIMESTAMP '2015-09-05 23:56:04', '%Y-%m-%d %H:%M:%S') AS timestamp;

    This returns "2015-09-05 23:56:04".

  3. Formatting a TIME value:

    SELECT FORMAT(TIME '23:56:04','%H:%M') AS time;

    This returns "23:56".

  4. Formatting different components of a TIMESTAMP value separately:

    SELECT 
    FORMAT(TIMESTAMP '2015-09-05 23:56:04', '%Y') AS year,
    FORMAT(TIMESTAMP '2015-09-05 23:56:04', '%m') AS month,
    FORMAT(TIMESTAMP '2015-09-05 23:56:04', '%d') AS day;

    This returns:

    year | month | day
    -----+-------+-----
    2015 | 09 | 05

Please note that the FORMAT function only accepts date, time, or timestamp values. If you try to format a value with an incorrect type, you will encounter an error.

Error Example

SELECT FORMAT('2015-09-05 23:56:04', '%Y-%m-%d %H') AS timestamp;

This will throw an error because the input value is a string, not a date, time, or timestamp value:

EvaluateError::UnsupportedExprForFormatFunction("2015-09-05 23:56:04".to_owned())
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/datetime/now/index.html b/docs/0.16.0/sql-syntax/functions/datetime/now/index.html new file mode 100644 index 00000000..83679a8d --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/datetime/now/index.html @@ -0,0 +1,17 @@ + + + + + +NOW | GlueSQL + + + + + +
+

NOW

The NOW() function in SQL returns the current date and time in UTC. You can use it to retrieve the current UTC timestamp, or as a default value for a TIMESTAMP column in a table.

Syntax

NOW()

Examples

Creating a table with a TIMESTAMP column and setting the default value to NOW()

CREATE TABLE Item (time TIMESTAMP DEFAULT NOW());

This creates a table named Item with a column time of the type TIMESTAMP. The default value for this column is the current UTC timestamp.

Inserting data into the table

INSERT INTO Item (time) VALUES
('2021-10-13T06:42:40.364832862'),
('9999-12-31T23:59:40.364832862');

Here we're inserting two rows into the Item table with specific timestamps.

Selecting rows where the timestamp is greater than the current timestamp

SELECT time FROM Item WHERE time > NOW();

This query selects the time column from the Item table where the time is greater than the current UTC timestamp. In this case, the result will be:

9999-12-31T23:59:40.364832862
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/datetime/to-date/index.html b/docs/0.16.0/sql-syntax/functions/datetime/to-date/index.html new file mode 100644 index 00000000..6a2fa813 --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/datetime/to-date/index.html @@ -0,0 +1,17 @@ + + + + + +TO_DATE | GlueSQL + + + + + +
+

TO_DATE

The TO_DATE function in SQL is used to convert a string into a DATE. This function takes two arguments, the string to be converted and a format string that specifies the format of the input string.

Syntax

TO_DATE(string, format)

Examples

Converting a string to a DATE

VALUES(TO_DATE('2017-06-15', '%Y-%m-%d'));

In this example, the string '2017-06-15' is converted into a DATE using the format '%Y-%m-%d', where %Y is the four-digit year, %m is the two-digit month, and %d is the two-digit day.

Converting a string to a DATE with a different format

SELECT TO_DATE('2017-jun-15','%Y-%b-%d') AS date;

In this example, the string '2017-jun-15' is converted into a DATE using the format '%Y-%b-%d', where %Y is the four-digit year, %b is the abbreviated month name, and %d is the two-digit day.

Error Handling

The TO_DATE function requires a string value as its first argument. If a non-string value is provided, it will return an error.

SELECT TO_DATE(DATE '2017-06-15','%Y-%m-%d') AS date;

In this case, the DATE '2017-06-15' is not a string and will cause an error.

Additionally, if the format string does not match the format of the input string, an error will also be returned. For example:

SELECT TO_DATE('2015-09-05', '%Y-%m') AS date;

In this case, the format string '%Y-%m' does not match the input string '2015-09-05', so an error will be returned.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/datetime/to-time/index.html b/docs/0.16.0/sql-syntax/functions/datetime/to-time/index.html new file mode 100644 index 00000000..8e0dffc3 --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/datetime/to-time/index.html @@ -0,0 +1,17 @@ + + + + + +TO_TIME | GlueSQL + + + + + +
+

TO_TIME

The TO_TIME function in SQL is used to convert a string into a TIME. This function takes two arguments, the string to be converted and a format string that specifies the format of the input string.

Syntax

TO_TIME(string, format)

Examples

Converting a string to a TIME

VALUES(TO_TIME('23:56:04', '%H:%M:%S'));

In this example, the string '23:56:04' is converted into a TIME using the format '%H:%M:%S', where %H is the two-digit hour, %M is the two-digit minute, and %S is the two-digit second.

Selecting a converted string to a TIME

SELECT TO_TIME('23:56:04','%H:%M:%S') AS time;

In this example, the string '23:56:04' is converted into a TIME using the format '%H:%M:%S' and selected as 'time'.

Error Handling

The TO_TIME function requires a string value as its first argument. If a non-string value is provided, it will return an error.

SELECT TO_TIME(TIME '23:56:04','%H:%M:%S') AS time;

In this case, the TIME '23:56:04' is not a string and will cause an error.

Additionally, if the format string does not match the format of the input string, an error will also be returned. For example:

SELECT TO_TIME('23:56', '%H:%M:%S') AS time;

In this case, the format string '%H:%M:%S' does not match the input string '23:56', so an error will be returned.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/datetime/to-timestamp/index.html b/docs/0.16.0/sql-syntax/functions/datetime/to-timestamp/index.html new file mode 100644 index 00000000..73931ae2 --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/datetime/to-timestamp/index.html @@ -0,0 +1,17 @@ + + + + + +TO_TIMESTAMP | GlueSQL + + + + + +
+

TO_TIMESTAMP

The TO_TIMESTAMP function in SQL is used to convert a string into a TIMESTAMP. This function takes two arguments, the string to be converted and a format string that specifies the format of the input string.

Syntax

TO_TIMESTAMP(string, format)

Examples

Converting a string to a TIMESTAMP

VALUES(TO_TIMESTAMP('2015-09-05 23:56:04', '%Y-%m-%d %H:%M:%S'));

In this example, the string '2015-09-05 23:56:04' is converted into a TIMESTAMP using the format '%Y-%m-%d %H:%M:%S', where %Y is the four-digit year, %m is the two-digit month, %d is the two-digit day, %H is the two-digit hour, %M is the two-digit minute, and %S is the two-digit second.

Selecting a converted string to a TIMESTAMP

SELECT TO_TIMESTAMP('2015-09-05 23:56:04', '%Y-%m-%d %H:%M:%S') AS timestamp;

In this example, the string '2015-09-05 23:56:04' is converted into a TIMESTAMP using the format '%Y-%m-%d %H:%M:%S' and selected as 'timestamp'.

Error Handling

The TO_TIMESTAMP function requires a string value as its first argument. If a non-string value is provided, it will return an error.

SELECT TO_TIMESTAMP(TIMESTAMP '2015-09-05 23:56:04','%Y-%m-%d') AS timestamp;

In this case, the TIMESTAMP '2015-09-05 23:56:04' is not a string and will cause an error.

Additionally, if the format string does not match the format of the input string, an error will also be returned. For example:

SELECT TO_TIMESTAMP('2015-09-05 23:56:04', '%Y-%m-%d %H:%M') AS timestamp;

In this case, the format string '%Y-%m-%d %H:%M' does not match the input string '2015-09-05 23:56:04', so an error will be returned.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/geometry/calc-distance/index.html b/docs/0.16.0/sql-syntax/functions/geometry/calc-distance/index.html new file mode 100644 index 00000000..201190e7 --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/geometry/calc-distance/index.html @@ -0,0 +1,17 @@ + + + + + +CALC_DISTANCE | GlueSQL + + + + + +
+

CALC_DISTANCE

The CALC_DISTANCE function is used to calculate the Euclidean distance between two Point type geographical coordinates.

Syntax

CALC_DISTANCE(point1, point2)

Parameters:

  • point1: The first geographical coordinate of type Point.
  • point2: The second geographical coordinate of type Point.

Examples

Consider the following table Foo:

CREATE TABLE Foo (
geo1 Point,
geo2 Point,
bar Float
);

With the following data:

INSERT INTO Foo VALUES (POINT(0.3134, 3.156), POINT(1.415, 3.231), 3);

Example 1: Calculate the distance between two points

SELECT CALC_DISTANCE(geo1, geo2) AS georesult FROM Foo;

Result:

georesult
1.104150152832485

Errors

  1. If the number of arguments is not 2, a FunctionArgsLengthNotMatching error will be thrown.
  2. If any of the arguments are not of type Point, a FunctionRequiresPointValue error will be thrown.
  3. If any of the arguments are NULL, the result will be NULL.
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/geometry/get-x/index.html b/docs/0.16.0/sql-syntax/functions/geometry/get-x/index.html new file mode 100644 index 00000000..d2f617db --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/geometry/get-x/index.html @@ -0,0 +1,17 @@ + + + + + +GET_X | GlueSQL + + + + + +
+

GET_X

The GET_X function returns the x-coordinate of a given POINT data type. It takes one POINT data type argument and returns a FLOAT value representing the x-coordinate.

Syntax

GET_X(point)

Parameters:

  • point: The geographical coordinate of type Point from which the X-coordinate will be extracted.

Examples

Consider the following table PointGroup:

CREATE TABLE PointGroup (
point_field POINT
);

With the following data:

INSERT INTO PointGroup VALUES (POINT(0.3134, 0.156));

Example 1: Get the X-coordinate from a point

SELECT GET_X(point_field) AS point_field FROM PointGroup;

Result:

point_field
0.3134

Example 2: Get the X-coordinate from a point using CAST

SELECT GET_X(CAST('POINT(0.1 -0.2)' AS POINT)) AS ptx;

Result:

ptx
0.1

Example 3: Get the X-coordinate from a point using POINT function

SELECT GET_X(POINT(0.1, -0.2)) AS ptx;

Result:

ptx
0.1

Errors

If the argument is not of type Point, a FunctionRequiresPointValue error will be thrown.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/geometry/get-y/index.html b/docs/0.16.0/sql-syntax/functions/geometry/get-y/index.html new file mode 100644 index 00000000..5f42b51a --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/geometry/get-y/index.html @@ -0,0 +1,17 @@ + + + + + +GET_Y | GlueSQL + + + + + +
+

GET_Y

The GET_Y function returns the y-coordinate of a given POINT data type. It takes one POINT data type argument and returns a FLOAT value representing the y-coordinate.

Syntax

GET_Y(point)

Parameters:

  • point: The geographical coordinate of type Point from which the Y-coordinate will be extracted.

Examples

Consider the following table PointGroup:

CREATE TABLE PointGroup (
point_field POINT
);

With the following data:

INSERT INTO PointGroup VALUES (POINT(0.3134, 0.156));

Example 1: Get the Y-coordinate from a point

SELECT GET_Y(point_field) AS point_field FROM PointGroup;

Result:

point_field
0.156

Example 2: Get the Y-coordinate from a point using CAST

SELECT GET_Y(CAST('POINT(0.1 -0.2)' AS POINT)) AS ptx;

Result:

ptx
-0.2

Example 3: Get the Y-coordinate from a point using POINT function

SELECT GET_Y(POINT(0.1, -0.2)) AS ptx;

Result:

ptx
-0.2

Errors

If the argument is not of type Point, a FunctionRequiresPointValue error will be thrown.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/geometry/point/index.html b/docs/0.16.0/sql-syntax/functions/geometry/point/index.html new file mode 100644 index 00000000..0cfbed9c --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/geometry/point/index.html @@ -0,0 +1,17 @@ + + + + + +POINT | GlueSQL + + + + + +
+

POINT

The POINT function creates a point value using the provided x and y coordinates. A point value represents a two-dimensional geometric point with a pair of floating-point numbers, often used for storing spatial data.

Syntax

POINT(x, y)

Examples

Create a table with a POINT data type column:

CREATE TABLE Foo (point_field POINT);

Insert a record with a point value:

INSERT INTO Foo VALUES (POINT(0.3134, 0.156));

Select the point_field column:

SELECT point_field AS point_field FROM Foo;

Update the point_field column:

UPDATE Foo SET point_field = POINT(2.0, 1.0) WHERE point_field = POINT(0.3134, 0.156);

Select the updated point_field column:

SELECT point_field AS point_field FROM Foo;

Delete the record with the specified point value:

DELETE FROM Foo WHERE point_field = POINT(2.0, 1.0);

Casting a string to a POINT:

SELECT CAST('POINT(-71.064544 42.28787)' AS POINT) AS pt;
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/list-map/append/index.html b/docs/0.16.0/sql-syntax/functions/list-map/append/index.html new file mode 100644 index 00000000..38dff559 --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/list-map/append/index.html @@ -0,0 +1,17 @@ + + + + + +APPEND | GlueSQL + + + + + +
+

APPEND

The APPEND function in SQL is used to append an element to a list.

Syntax

APPEND(list, element)
  • list: The list to which you want to append the element.
  • element: The element that you want to append to the list.

Examples

First, create a table named Append with columns for the list, an integer element, and a text element:

CREATE TABLE Append (
id INTEGER,
items LIST,
element INTEGER,
element2 TEXT
);

Insert some data into the Append table:

INSERT INTO Append VALUES
(1, '[1, 2, 3]', 4, 'Foo');

Use the APPEND function to append the integer element to the list:

SELECT APPEND(items, element) AS myappend FROM Append;

Use the APPEND function to append the text element to the list:

SELECT APPEND(items, element2) AS myappend FROM Append;

The APPEND function requires a list as the first parameter. If you try to use it with a non-list value, an error will occur:

SELECT APPEND(element, element2) AS myappend FROM Append;

You can also use the APPEND function when inserting data into a table. First, create a table named Foo with a column for the list:

CREATE TABLE Foo (
elements LIST
);

Then, insert data into the Foo table using the APPEND function:

INSERT INTO Foo VALUES (APPEND(CAST('[1, 2, 3]' AS LIST), 4));

Finally, retrieve the list from the Foo table:

SELECT elements AS myappend FROM Foo;
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/list-map/concat/index.html b/docs/0.16.0/sql-syntax/functions/list-map/concat/index.html new file mode 100644 index 00000000..f79d5341 --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/list-map/concat/index.html @@ -0,0 +1,17 @@ + + + + + +CONCAT | GlueSQL + + + + + +
+

CONCAT

The CONCAT function is used to concatenate two or more list values together.

Syntax

CONCAT(list_value1, list_value2, ...)

Parameters:

  • list_value1, list_value2, ...: List values that will be concatenated.

Examples

Consider the following table ListTypeConcat:

CREATE TABLE ListTypeConcat (
id INTEGER,
items LIST,
items2 LIST
);

With the following data:

INSERT INTO ListTypeConcat VALUES
(1, '[1, 2, 3]', '["one", "two", "three"]');

Example 1: CONCAT two lists

SELECT CONCAT(items, items2) AS myconcat FROM ListTypeConcat;

Result:

myconcat
[1, 2, 3, "one", "two", "three"]
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/list-map/prepend/index.html b/docs/0.16.0/sql-syntax/functions/list-map/prepend/index.html new file mode 100644 index 00000000..d891b873 --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/list-map/prepend/index.html @@ -0,0 +1,17 @@ + + + + + +PREPEND | GlueSQL + + + + + +
+

PREPEND

The PREPEND function in SQL is used to prepend an element to a list.

Syntax

PREPEND(list, element)
  • list: The list to which you want to prepend the element.
  • element: The element that you want to prepend to the list.

Examples

First, create a table named Prepend with columns for the list, an integer element, and a text element:

CREATE TABLE Prepend (
id INTEGER,
items LIST,
element INTEGER,
element2 TEXT
);

Insert some data into the Prepend table:

INSERT INTO Prepend VALUES
(1, '[1, 2, 3]', 0, 'Foo');

Use the PREPEND function to prepend the integer element to the list:

SELECT PREPEND(items, element) AS myprepend FROM Prepend;

Use the PREPEND function to prepend the text element to the list:

SELECT PREPEND(items, element2) AS myprepend FROM Prepend;

The PREPEND function requires a list as the first parameter. If you try to use it with a non-list value, an error will occur:

SELECT PREPEND(element, element2) AS myprepend FROM Prepend;

You can also use the PREPEND function when inserting data into a table. First, create a table named Foo with a column for the list:

CREATE TABLE Foo (
elements LIST
);

Then, insert data into the Foo table using the PREPEND function:

INSERT INTO Foo VALUES (PREPEND(CAST('[1, 2, 3]' AS LIST), 0));

Finally, retrieve the list from the Foo table:

SELECT elements AS myprepend FROM Foo;
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/list-map/slice/index.html b/docs/0.16.0/sql-syntax/functions/list-map/slice/index.html new file mode 100644 index 00000000..dd93dbb4 --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/list-map/slice/index.html @@ -0,0 +1,17 @@ + + + + + +SLICE | GlueSQL + + + + + +
+

SLICE

The SLICE statement is a function in GlueSQL that allows you to retrieve a subsection of a list. It is analogous to slicing operations in many programming languages.

Syntax

SELECT SLICE(column_name, start_index, length) AS alias_name FROM table_name;
  • column_name: Name of the column containing the list.
  • start_index: The starting index from where the slice should begin. This value can be negative.
  • length: The number of elements to be included in the slice.

Examples

Consider the following table Test:

CREATE TABLE Test (
list LIST
);

With the following data:

INSERT INTO Test VALUES
('[1,2,3,4]');

1. Basic Slicing

Retrieve the first 2 elements from a list.

SELECT SLICE(list, 0, 2) AS value FROM Test;

Result:

[1, 2]

2. Slicing Beyond List Length

If the combined start index and length exceed the list size, SLICE will return all possible elements without error.

SELECT SLICE(list, 2, 5) AS value FROM Test;

Result:

[3, 4]

3. Start Index Beyond List Length

If the start index alone exceeds the list size, SLICE will return an empty list.

SELECT SLICE(list, 100, 5) AS value FROM Test;

Result:

[]

4. Using Negative Start Index

A negative start index counts from the end of the list.

SELECT SLICE(list, -1, 1) AS value FROM Test;

Result:

[4]

Another example of a negative start index.

SELECT SLICE(list, -2, 4) AS value FROM Test;

Result:

[3, 4]

If the absolute value of the negative start index exceeds the list length, it is treated as index 0.

SELECT SLICE(list, -234, 4) AS value FROM Test;

Result:

[1, 2, 3, 4]

Errors

  • Using a non-list value for slicing will result in an error: ListTypeRequired.
  • Using a non-integer value for the start index or length will result in an error: FunctionRequiresIntegerValue("SLICE").
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/list-map/splice/index.html b/docs/0.16.0/sql-syntax/functions/list-map/splice/index.html new file mode 100644 index 00000000..c65be8e2 --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/list-map/splice/index.html @@ -0,0 +1,17 @@ + + + + + +SQL Function - "SPLICE" | GlueSQL + + + + + +
+

SQL Function - "SPLICE"

The "SPLICE" function in GlueSQL is used to modify elements in a list. It allows you to remove or replace elements in a list. The syntax for the "SPLICE" function is as follows:

SPLICE(list1, start_index, end_index [, list2])
  • list1: The list you want to modify.
  • start_index: The position at which you want to start the modification.
  • end_index: The exclusive end position for the modification.
  • list2 (optional): A list of elements to insert in place of the removed elements.

Example

We can use the "SPLICE" function to modify the list in various ways:

  1. Remove elements from a list:
-- Remove elements at 1, 2 from the list '[1, 2, 3]'
SELECT SPLICE(CAST('[1, 2, 3, 4, 5]' AS List), 1, 3) AS result;
-- Output: '[1, 4, 5]'
  1. Replace elements in a list:
-- Replace elements at 1, 2, 3 with '[100, 99]' in the list '[1, 2, 3, 4, 5]'
SELECT SPLICE(CAST('[1, 2, 3, 4, 5]' AS List), 1, 4, CAST('[100, 99]' AS List)) AS result;
-- Output: '[1, 100, 99, 5]'
  1. 'start' is processed so that it is not less than 0 and 'end' is not greater than the length of the list.
SELECT SPLICE(CAST('[1, 2, 3]' AS List), -1, 2, CAST('[100, 99]' AS List)) AS result;
-- Output: '[100, 99, 3]'

Error

If you use the "SPLICE" function with invalid inputs, it will result in an error. For example:

-- Using SPLICE on a non-list value will result in an error.
SELECT SPLICE(3, 1, 2) AS result;
-- EvaluateError::ListTypeRequired
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/math/abs/index.html b/docs/0.16.0/sql-syntax/functions/math/abs/index.html new file mode 100644 index 00000000..98aa2476 --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/math/abs/index.html @@ -0,0 +1,17 @@ + + + + + +ABS | GlueSQL + + + + + +
+

ABS

The ABS function is used to calculate the absolute value of a number. It takes a single numeric argument and returns the absolute value of that number. The argument can be an integer, decimal, or float value.

Syntax

ABS(value)
  • value: A numeric expression for which the absolute value is to be calculated.

Examples

Let's consider a table named SingleItem with the following schema:

CREATE TABLE SingleItem (id INTEGER, int8 INT8, dec DECIMAL);

Insert a row into the SingleItem table:

INSERT INTO SingleItem VALUES (0, -1, -2);

Example 1: Using ABS with integer values

SELECT ABS(1) AS ABS1, 
ABS(-1) AS ABS2,
ABS(+1) AS ABS3
FROM SingleItem;

Result:

 ABS1 | ABS2 | ABS3 
------+------+------
1 | 1 | 1

Example 2: Using ABS with float values

SELECT ABS(1.0) AS ABS1, 
ABS(-1.0) AS ABS2,
ABS(+1.0) AS ABS3
FROM SingleItem;

Result:

 ABS1 | ABS2 | ABS3 
------+------+------
1.0 | 1.0 | 1.0

Example 3: Using ABS with table columns

SELECT ABS(id) AS ABS1, 
ABS(int8) AS ABS2,
ABS(dec) AS ABS3
FROM SingleItem;

Result:

 ABS1 | ABS2 | ABS3 
------+------+------
0 | 1 | 2

Example 4: Using ABS with NULL values

SELECT ABS(NULL) AS ABS FROM SingleItem;

Result:

  ABS  
-------
(null)

Errors

The ABS function requires a numeric value as its argument. Using non-numeric values or more than one argument will result in an error.

Example 5: Using ABS with non-numeric values

SELECT ABS('string') AS ABS FROM SingleItem;

Error: Function requires a numeric value.

Example 6: Using ABS with multiple arguments

SELECT ABS('string', 'string2') AS ABS FROM SingleItem;

Error: Function expects 1 argument, but 2 were provided.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/math/acos/index.html b/docs/0.16.0/sql-syntax/functions/math/acos/index.html new file mode 100644 index 00000000..5b9757f3 --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/math/acos/index.html @@ -0,0 +1,17 @@ + + + + + +ACOS | GlueSQL + + + + + +
+

ACOS

The ACOS function is used to calculate the arccosine (inverse cosine) of a number. It takes a single numeric argument, which should be a float value in the range of -1 to 1, and returns the arccosine of that number in radians.

Syntax

ACOS(value)
  • value: A numeric expression for which the arccosine is to be calculated. The value should be in the range of -1 to 1.

Examples

Let's consider a table named SingleItem with the following schema:

CREATE TABLE SingleItem (id INTEGER);

Insert a row into the SingleItem table:

INSERT INTO SingleItem VALUES (0);

Example 1: Using ACOS with float values

SELECT ACOS(0.5) AS acos1, ACOS(1) AS acos2 FROM SingleItem;

Result:

     acos1      |     acos2
----------------+---------------
1.0471975511966 | 0.0

Example 2: Using ACOS with NULL values

SELECT ACOS(NULL) AS acos FROM SingleItem;

Result:

  acos
-------
(null)

Errors

The ACOS function requires a numeric value in the range of -1 to 1 as its argument. Using non-numeric values or more than one argument will result in an error.

Example 3: Using ACOS with non-numeric values

SELECT ACOS('string') AS acos FROM SingleItem;

Error: Function requires a numeric value.

Example 4: Using ACOS with multiple arguments

SELECT ACOS(1.0, 2.0) AS acos FROM SingleItem;

Error: Function expects 1 argument, but 2 were provided.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/math/asin/index.html b/docs/0.16.0/sql-syntax/functions/math/asin/index.html new file mode 100644 index 00000000..df525f60 --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/math/asin/index.html @@ -0,0 +1,17 @@ + + + + + +ASIN | GlueSQL + + + + + +
+

ASIN

The ASIN function is used to calculate the arcsine (inverse sine) of a number. It takes a single numeric argument, which should be a float value in the range of -1 to 1, and returns the arcsine of that number in radians.

Syntax

ASIN(value)
  • value: A numeric expression for which the arcsine is to be calculated. The value should be in the range of -1 to 1.

Examples

Let's consider a table named SingleItem with the following schema:

CREATE TABLE SingleItem (id INTEGER);

Insert a row into the SingleItem table:

INSERT INTO SingleItem VALUES (0);

Example 1: Using ASIN with float values

SELECT ASIN(0.5) AS asin1, ASIN(1) AS asin2 FROM SingleItem;

Result:

     asin1      |     asin2
----------------+---------------
0.5235987755983 | 1.5707963267949

Example 2: Using ASIN with NULL values

SELECT ASIN(NULL) AS asin FROM SingleItem;

Result:

  asin
-------
(null)

Errors

The ASIN function requires a numeric value in the range of -1 to 1 as its argument. Using non-numeric values or more than one argument will result in an error.

Example 3: Using ASIN with non-numeric values

SELECT ASIN('string') AS asin FROM SingleItem;

Error: Function requires a numeric value.

Example 4: Using ASIN with multiple arguments

SELECT ASIN(1.0, 2.0) AS sin FROM SingleItem;

Error: Function expects 1 argument, but 2 were provided.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/math/atan/index.html b/docs/0.16.0/sql-syntax/functions/math/atan/index.html new file mode 100644 index 00000000..e2a71c0f --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/math/atan/index.html @@ -0,0 +1,17 @@ + + + + + +ATAN | GlueSQL + + + + + +
+

ATAN

The ATAN function is used to calculate the arctangent (inverse tangent) of a number. It takes a single numeric argument, and returns the arctangent of that number in radians.

Syntax

ATAN(value)
  • value: A numeric expression for which the arctangent is to be calculated.

Examples

Let's consider a table named SingleItem with the following schema:

CREATE TABLE SingleItem (id INTEGER);

Insert a row into the SingleItem table:

INSERT INTO SingleItem VALUES (0);

Example 1: Using ATAN with float values

SELECT ATAN(0.5) AS atan1, ATAN(1) AS atan2 FROM SingleItem;

Result:

    atan1     |    atan2
--------------+---------------
0.463647609 | 0.785398163

Example 2: Using ATAN with NULL values

SELECT ATAN(NULL) AS atan FROM SingleItem;

Result:

  atan
-------
(null)

Errors

The ATAN function requires a numeric value as its argument. Using non-numeric values or more than one argument will result in an error.

Example 3: Using ATAN with non-numeric values

SELECT ATAN('string') AS atan FROM SingleItem;

Error: Function requires a numeric value.

Example 4: Using ATAN with multiple arguments

SELECT ATAN(1.0, 2.0) AS atan FROM SingleItem;

Error: Function expects 1 argument, but 2 were provided.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/math/ceil/index.html b/docs/0.16.0/sql-syntax/functions/math/ceil/index.html new file mode 100644 index 00000000..726fc0ff --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/math/ceil/index.html @@ -0,0 +1,17 @@ + + + + + +CEIL | GlueSQL + + + + + +
+

CEIL

The CEIL function is used to round a number up to the nearest integer value. It takes a single floating-point or integer value as its argument and returns a floating-point value.

Syntax

CEIL(value)

Examples

Let's consider a table named SingleItem with the following schema:

CREATE TABLE SingleItem (id INTEGER);

Insert a row into the SingleItem table:

INSERT INTO SingleItem VALUES (0);

Example 1: Using CEIL function

SELECT CEIL(0.3) AS ceil1,
CEIL(-0.8) AS ceil2,
CEIL(10) AS ceil3,
CEIL(6.87421) AS ceil4
FROM SingleItem;

Result:

ceil1 | ceil2 | ceil3 | ceil4
------+-------+-------+-------
1.0 | 0.0 | 10.0 | 7.0

Note that the returned values are floating-point numbers, even though they represent integer values.

Errors

The CEIL function expects a floating-point or integer value as its argument. Providing any other type, such as a string or boolean, will result in an error.

Example 2: Using CEIL with a string argument

SELECT CEIL('string') AS ceil FROM SingleItem;

Error: Function requires a floating-point or integer value.

Example 3: Using CEIL with a boolean argument

SELECT CEIL(TRUE) AS ceil FROM SingleItem;

Error: Function requires a floating-point or integer value.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/math/cos/index.html b/docs/0.16.0/sql-syntax/functions/math/cos/index.html new file mode 100644 index 00000000..479e9e14 --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/math/cos/index.html @@ -0,0 +1,17 @@ + + + + + +COS | GlueSQL + + + + + +
+

COS

The COS function is used to calculate the cosine of a number. It takes a single numeric argument (angle in radians) and returns the cosine of that angle.

Syntax

COS(value)
  • value: A numeric expression (angle in radians) for which the cosine is to be calculated.

Examples

Let's consider a table named SingleItem with the following schema:

CREATE TABLE SingleItem (id INTEGER);

Insert a row into the SingleItem table:

INSERT INTO SingleItem VALUES (0);

Example 1: Using COS with float values

SELECT COS(0.5) AS cos1, COS(1) AS cos2 FROM SingleItem;

Result:

    cos1     |    cos2
-------------+--------------
0.877582562 | 0.540302306

Example 2: Using COS with NULL values

SELECT COS(NULL) AS cos FROM SingleItem;

Result:

  cos
-------
(null)

Errors

The COS function requires a numeric value as its argument. Using non-numeric values or more than one argument will result in an error.

Example 3: Using COS with non-numeric values

SELECT COS('string') AS cos FROM SingleItem;

Error: Function requires a numeric value.

Example 4: Using COS with multiple arguments

SELECT COS(1.0, 2.0) AS cos FROM SingleItem;

Error: Function expects 1 argument, but 2 were provided.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/math/degrees/index.html b/docs/0.16.0/sql-syntax/functions/math/degrees/index.html new file mode 100644 index 00000000..f9a078e7 --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/math/degrees/index.html @@ -0,0 +1,17 @@ + + + + + +DEGREES | GlueSQL + + + + + +
+

DEGREES

The DEGREES function is used to convert a given angle value from radians to degrees. It takes a single numeric argument (angle in radians) and returns the angle in degrees.

Syntax

DEGREES(value)
  • value: A numeric expression (angle in radians) to be converted to degrees.

Examples

Let's consider a table named SingleItem with the following schema:

CREATE TABLE SingleItem (id FLOAT);

Insert a row into the SingleItem table:

INSERT INTO SingleItem VALUES (0);

Example 1: Using DEGREES with float values

SELECT
DEGREES(180.0) as degrees_1,
DEGREES(360.0) as degrees_2
FROM SingleItem;

Result:

   degrees_1 | degrees_2
-------------+-------------
10313.240312 | 20626.480624

Example 2: Using DEGREES with integer values

SELECT DEGREES(90) as degrees_with_int FROM SingleItem;

Result:

degrees_with_int
-----------------
5156.620156

Example 3: Using DEGREES with zero

SELECT DEGREES(0) as degrees_with_zero FROM SingleItem;

Result:

degrees_with_zero
------------------
0.0

Errors

The DEGREES function requires a numeric value as its argument. Using non-numeric values or more than one argument will result in an error.

Example 4: Using DEGREES with non-numeric values

SELECT DEGREES('string') AS degrees FROM SingleItem;

Error: Function requires a numeric value.

Example 5: Using DEGREES with multiple arguments

SELECT DEGREES(0, 0) as degrees_arg2 FROM SingleItem;

Error: Function expects 1 argument, but 2 were provided.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/math/div/index.html b/docs/0.16.0/sql-syntax/functions/math/div/index.html new file mode 100644 index 00000000..3d951b70 --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/math/div/index.html @@ -0,0 +1,17 @@ + + + + + +DIV | GlueSQL + + + + + +
+

DIV

The DIV function is used to perform integer division. It takes two arguments (a dividend and a divisor) and returns the integer quotient of the division operation. Both dividend and divisor can be FLOAT or INTEGER type. The return type of the function is INTEGER.

Example

The following example demonstrates the usage of the DIV function in a SQL query:

CREATE TABLE FloatDiv (
dividend FLOAT DEFAULT DIV(30, 11),
divisor FLOAT DEFAULT DIV(3, 2)
);

INSERT INTO FloatDiv (dividend, divisor) VALUES (12.0, 3.0), (12.34, 56.78), (-12.3, 4.0);

SELECT DIV(dividend, divisor) FROM FloatDiv;

This will return the following result:

DIV(dividend, divisor)
4
0
-4

Errors

  1. If the divisor is zero, a DivisorShouldNotBeZero error will be raised.
  2. If either of the arguments is not of FLOAT or INTEGER type, a FunctionRequiresFloatOrIntegerValue error will be raised.
  3. If the number of arguments provided to the function is not equal to 2, a FunctionArgsLengthNotMatching error will be raised.
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/math/exp/index.html b/docs/0.16.0/sql-syntax/functions/math/exp/index.html new file mode 100644 index 00000000..019e849f --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/math/exp/index.html @@ -0,0 +1,17 @@ + + + + + +EXP | GlueSQL + + + + + +
+

EXP

The EXP function is used to calculate the exponential value of a number. It takes a single FLOAT or INTEGER argument and returns a FLOAT value representing the exponential value of the given number.

Example

The following example demonstrates the usage of the EXP function in a SQL query:

SELECT
EXP(2.0) as exp1,
EXP(5.5) as exp2;

This will return the following result:

exp1           | exp2
---------------+-------------------
2.0_f64.exp() | 5.5_f64.exp()

Errors

  1. If the argument is not of FLOAT or INTEGER type, a FunctionRequiresFloatValue error will be raised.
  2. If the number of arguments provided to the function is not equal to 1, a FunctionArgsLengthNotMatching error will be raised.
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/math/floor/index.html b/docs/0.16.0/sql-syntax/functions/math/floor/index.html new file mode 100644 index 00000000..e6eed101 --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/math/floor/index.html @@ -0,0 +1,17 @@ + + + + + +FLOOR | GlueSQL + + + + + +
+

FLOOR

The FLOOR function is used to round a number down to the nearest integer value. It takes a single floating-point or integer value as its argument and returns a floating-point value.

Syntax

FLOOR(value)

Examples

Let's consider a table named SingleItem with the following schema:

CREATE TABLE SingleItem (id INTEGER);

Insert a row into the SingleItem table:

INSERT INTO SingleItem VALUES (0);

Example 1: Using FLOOR function

SELECT
FLOOR(0.3) as floor1,
FLOOR(-0.8) as floor2,
FLOOR(10) as floor3,
FLOOR(6.87421) as floor4
FROM SingleItem;

Result:

floor1 | floor2 | floor3 | floor4
-------+--------+--------+--------
0.0 | -1.0 | 10.0 | 6.0

Note that the returned values are floating-point numbers, even though they represent integer values.

Errors

The FLOOR function expects a floating-point or integer value as its argument. Providing any other type, such as a string or boolean, will result in an error.

Example 2: Using FLOOR with a string argument

SELECT FLOOR('string') AS floor FROM SingleItem;

Error: Function requires a floating-point or integer value.

Example 3: Using FLOOR with a boolean argument

SELECT FLOOR(TRUE) AS floor FROM SingleItem;

Error: Function requires a floating-point or integer value.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/math/gcd/index.html b/docs/0.16.0/sql-syntax/functions/math/gcd/index.html new file mode 100644 index 00000000..4ee37b4c --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/math/gcd/index.html @@ -0,0 +1,17 @@ + + + + + +GCD | GlueSQL + + + + + +
+

GCD

The GCD function is used to find the greatest common divisor (GCD) of two integers. It takes two INTEGER arguments and returns an INTEGER value representing the greatest common divisor of the given integers.

Example

The following example demonstrates the usage of the GCD function in a SQL query:

CREATE TABLE GcdI64 (
left INTEGER NULL DEFAULT GCD(3, 4),
right INTEGER NULL
);

INSERT INTO GcdI64 VALUES (0, 3), (2, 4), (6, 8), (3, 5), (1, NULL), (NULL, 1);

SELECT GCD(left, right) AS test FROM GcdI64;

This will return the following result:

test
3
2
2
1
NULL
NULL

Errors

  1. If either of the arguments is not of INTEGER type, a FunctionRequiresIntegerValue error will be raised.
  2. If the number of arguments provided to the function is not equal to 2, a FunctionArgsLengthNotMatching error will be raised.
  3. If either of the arguments is the minimum i64 value (-9223372036854775808), an overflow occurs when attempting to take the absolute value. In this case, a GcdLcmOverflowError is raised.
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/math/lcm/index.html b/docs/0.16.0/sql-syntax/functions/math/lcm/index.html new file mode 100644 index 00000000..65bd34f5 --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/math/lcm/index.html @@ -0,0 +1,17 @@ + + + + + +LCM | GlueSQL + + + + + +
+

LCM

The LCM function is used to find the least common multiple (LCM) of two integers. It takes two INTEGER arguments and returns an INTEGER value representing the least common multiple of the given integers.

Example

The following example demonstrates the usage of the LCM function in a SQL query:

CREATE TABLE LcmI64 (
left INTEGER NULL,
right INTEGER NULL
);

INSERT INTO LcmI64 VALUES (0, 3), (2, 4), (6, 8), (3, 5), (1, NULL), (NULL, 1);

SELECT LCM(left, right) AS test FROM LcmI64;

This will return the following result:

test
0
4
24
15
NULL
NULL

Errors

  1. If either of the arguments is not of INTEGER type, a FunctionRequiresIntegerValue error will be raised.
  2. If the number of arguments provided to the function is not equal to 2, a FunctionArgsLengthNotMatching error will be raised.
  3. If either of the arguments is the minimum i64 value (-9223372036854775808), an overflow occurs when attempting to calculate the gcd, which is then used in the lcm calculation. In this case, an GcdLcmOverflowError is raised.
  4. If the calculated result of lcm is outside the valid range of i64 (-9223372036854775808 to 9223372036854775807), a LcmResultOutOfRange error is raised. This may occur with large prime numbers.
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/math/ln/index.html b/docs/0.16.0/sql-syntax/functions/math/ln/index.html new file mode 100644 index 00000000..b18cb975 --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/math/ln/index.html @@ -0,0 +1,17 @@ + + + + + +LN | GlueSQL + + + + + +
+

LN

The LN function is used to calculate the natural logarithm (base e) of a number. It takes a single FLOAT or INTEGER argument and returns a FLOAT value representing the natural logarithm of the given number.

Example

The following example demonstrates the usage of the LN function in a SQL query:

CREATE TABLE SingleItem (id INTEGER DEFAULT LN(10));

INSERT INTO SingleItem VALUES (0);

SELECT
LN(64.0) as ln1,
LN(0.04) as ln2
FROM SingleItem;

This will return the following result:

ln1     | ln2
--------+-------------------
4.1589 | -3.2189

Errors

  1. If the argument is not of FLOAT or INTEGER type, a FunctionRequiresFloatValue error will be raised.
  2. If the number of arguments provided to the function is not equal to 1, a FunctionArgsLengthNotMatching error will be raised.
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/math/log/index.html b/docs/0.16.0/sql-syntax/functions/math/log/index.html new file mode 100644 index 00000000..8272d4b1 --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/math/log/index.html @@ -0,0 +1,17 @@ + + + + + +LOG | GlueSQL + + + + + +
+

LOG

The LOG function calculates the logarithm of a number with a specified base. It takes two FLOAT or INTEGER arguments and returns a FLOAT value representing the logarithm of the first argument with the base specified by the second argument.

Example

The following example demonstrates the usage of the LOG function in a SQL query:

CREATE TABLE SingleItem (id INTEGER DEFAULT LOG(2, 64));

INSERT INTO SingleItem VALUES (0);

SELECT
LOG(64.0, 2.0) as log_1,
LOG(0.04, 10.0) as log_2
FROM SingleItem;

This will return the following result:

log_1 | log_2
------+-------------------
6.0 | -1.39794

Errors

  1. If either of the arguments is not of FLOAT or INTEGER type, a FunctionRequiresFloatValue error will be raised.
  2. If the number of arguments provided to the function is not equal to 2, a FunctionArgsLengthNotMatching error will be raised.
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/math/log10/index.html b/docs/0.16.0/sql-syntax/functions/math/log10/index.html new file mode 100644 index 00000000..d92f785d --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/math/log10/index.html @@ -0,0 +1,17 @@ + + + + + +LOG10 | GlueSQL + + + + + +
+

LOG10

The LOG10 function is used to calculate the base-10 logarithm of a number. It takes a single FLOAT or INTEGER argument and returns a FLOAT value representing the base-10 logarithm of the given number.

Example

The following example demonstrates the usage of the LOG10 function in a SQL query:

CREATE TABLE SingleItem (id INTEGER DEFAULT LOG10(100));

INSERT INTO SingleItem VALUES (0);

SELECT
LOG10(64.0) as log10_1,
LOG10(0.04) as log10_2
FROM SingleItem;

This will return the following result:

log10_1 | log10_2
--------+-------------------
1.8062 | -1.3979

Errors

  1. If the argument is not of FLOAT or INTEGER type, a FunctionRequiresFloatValue error will be raised.
  2. If the number of arguments provided to the function is not equal to 1, a FunctionArgsLengthNotMatching error will be raised.
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/math/log2/index.html b/docs/0.16.0/sql-syntax/functions/math/log2/index.html new file mode 100644 index 00000000..ad9d7206 --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/math/log2/index.html @@ -0,0 +1,17 @@ + + + + + +LOG2 | GlueSQL + + + + + +
+

LOG2

The LOG2 function is used to calculate the base-2 logarithm of a number. It takes a single FLOAT or INTEGER argument and returns a FLOAT value representing the base-2 logarithm of the given number.

Example

The following example demonstrates the usage of the LOG2 function in a SQL query:

CREATE TABLE SingleItem (id INTEGER DEFAULT LOG2(1024));

INSERT INTO SingleItem VALUES (0);

SELECT
LOG2(64.0) as log2_1,
LOG2(0.04) as log2_2
FROM SingleItem;

This will return the following result:

log2_1 | log2_2
-------+-------------------
6.0 | -4.5850

Errors

  1. If the argument is not of FLOAT or INTEGER type, a FunctionRequiresFloatValue error will be raised.
  2. If the number of arguments provided to the function is not equal to 1, a FunctionArgsLengthNotMatching error will be raised.
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/math/mod/index.html b/docs/0.16.0/sql-syntax/functions/math/mod/index.html new file mode 100644 index 00000000..5a9cc58a --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/math/mod/index.html @@ -0,0 +1,17 @@ + + + + + +MOD | GlueSQL + + + + + +
+

MOD

The MOD function is used to calculate the remainder of a division operation. It takes two arguments (a dividend and a divisor) and returns the remainder of the division operation. Both dividend and divisor can be FLOAT or INTEGER type. The return type of the function is FLOAT.

Example

The following example demonstrates the usage of the MOD function in a SQL query:

CREATE TABLE FloatDiv (
dividend FLOAT DEFAULT MOD(30, 11),
divisor FLOAT DEFAULT DIV(3, 2)
);

INSERT INTO FloatDiv (dividend, divisor) VALUES (12.0, 3.0), (12.34, 56.78), (-12.3, 4.0);

SELECT MOD(dividend, divisor) FROM FloatDiv;

This will return the following result:

MOD(dividend, divisor)
0.0
12.34
-0.3

Errors

  1. If the divisor is zero, a DivisorShouldNotBeZero error will be raised.
  2. If either of the arguments is not of FLOAT or INTEGER type, a FunctionRequiresFloatOrIntegerValue error will be raised.
  3. If the number of arguments provided to the function is not equal to 2, a FunctionArgsLengthNotMatching error will be raised.
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/math/pi/index.html b/docs/0.16.0/sql-syntax/functions/math/pi/index.html new file mode 100644 index 00000000..ae235a31 --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/math/pi/index.html @@ -0,0 +1,17 @@ + + + + + +PI | GlueSQL + + + + + +
+

PI

The PI function is used to retrieve the mathematical constant π (pi), which is approximately 3.141592653589793. The function takes no arguments.

Syntax

PI()

Examples

Let's consider a table named SingleItem with the following schema:

CREATE TABLE SingleItem (id FLOAT);

Insert a row into the SingleItem table:

INSERT INTO SingleItem VALUES (0);

Example 1: Using PI function

SELECT PI() as pi FROM SingleItem;

Result:

        pi
----------------
3.141592653589793

Errors

The PI function expects no arguments. Providing any arguments will result in an error.

Example 2: Using PI with an argument

SELECT PI(0) as pi FROM SingleItem;

Error: Function expects 0 arguments, but 1 was provided.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/math/power/index.html b/docs/0.16.0/sql-syntax/functions/math/power/index.html new file mode 100644 index 00000000..e68daf0f --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/math/power/index.html @@ -0,0 +1,17 @@ + + + + + +POWER | GlueSQL + + + + + +
+

POWER

The POWER function is used to raise a number to the power of another number. It takes two arguments, the base and the exponent, both of which must be of the FLOAT type. The result will also be of the FLOAT type.

Syntax

POWER(base, exponent)

Examples

  1. Using the POWER function:
SELECT POWER(2.0, 4) as power_1;
-- Result: 16.0
  1. Using the POWER function with a decimal:
SELECT POWER(0.07, 3) as power_2;
-- Result: 0.000343
  1. Using the POWER function with zero:
SELECT POWER(0, 4) as power_with_zero;
-- Result: 0.0

SELECT POWER(3, 0) as power_to_zero;
-- Result: 1.0

Error Cases

  1. The POWER function requires both arguments to be of FLOAT type:
SELECT POWER('string', 'string') AS power;
-- Error: FunctionRequiresFloatValue("POWER")
  1. The POWER function requires the base to be of FLOAT type:
SELECT POWER('string', 2.0) AS power;
-- Error: FunctionRequiresFloatValue("POWER")
  1. The POWER function requires the exponent to be of FLOAT type:
SELECT POWER(2.0, 'string') AS power;
-- Error: FunctionRequiresFloatValue("POWER")
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/math/radians/index.html b/docs/0.16.0/sql-syntax/functions/math/radians/index.html new file mode 100644 index 00000000..ba428ce6 --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/math/radians/index.html @@ -0,0 +1,17 @@ + + + + + +RADIANS | GlueSQL + + + + + +
+

RADIANS

The RADIANS function is used to convert a given angle value from degrees to radians. It takes a single numeric argument (angle in degrees) and returns the angle in radians.

Syntax

RADIANS(value)
  • value: A numeric expression (angle in degrees) to be converted to radians.

Examples

Let's consider a table named SingleItem with the following schema:

CREATE TABLE SingleItem (id FLOAT);

Insert a row into the SingleItem table:

INSERT INTO SingleItem VALUES (0);

Example 1: Using RADIANS with float values

SELECT
RADIANS(180.0) as radians_1,
RADIANS(360.0) as radians_2
FROM SingleItem;

Result:

    radians_1 | radians_2
-------------+-------------
3.141593 | 6.283185

Example 2: Using RADIANS with integer values

SELECT RADIANS(90) as radians_with_int FROM SingleItem;

Result:

radians_with_int
-----------------
1.570796

Example 3: Using RADIANS with zero

SELECT RADIANS(0) as radians_with_zero FROM SingleItem;

Result:

radians_with_zero
------------------
0.0

Errors

The RADIANS function requires a numeric value as its argument. Using non-numeric values or more than one argument will result in an error.

Example 4: Using RADIANS with non-numeric values

SELECT RADIANS('string') AS radians FROM SingleItem;

Error: Function requires a numeric value.

Example 5: Using RADIANS with multiple arguments

SELECT RADIANS(0, 0) as radians_arg2 FROM SingleItem;

Error: Function expects 1 argument, but 2 were provided.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/math/rand/index.html b/docs/0.16.0/sql-syntax/functions/math/rand/index.html new file mode 100644 index 00000000..d1db8a80 --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/math/rand/index.html @@ -0,0 +1,17 @@ + + + + + +RAND | GlueSQL + + + + + +
+

RAND

The RAND function is used to generate a random float value between 0 (inclusive) and 1 (exclusive). The function takes an optional seed value, which must be of the FLOAT type. If a seed value is provided, the random number generator will be initialized with that seed, producing a deterministic sequence of random numbers.

Syntax

RAND([seed])

Examples

  1. Using the RAND function without a seed:
SELECT RAND() AS rand;
-- Result: A random float between 0 and 1
  1. Using the RAND function with a seed:
SELECT RAND(123) AS rand1, RAND(789.0) AS rand2;
-- Result: 0.17325464426155657, 0.9635218234007941
  1. Using the RAND function with NULL:
SELECT RAND(NULL) AS rand;
-- Result: NULL

Error Cases

  1. The RAND function requires the argument to be of FLOAT type, if provided:
SELECT RAND('string') AS rand;
-- Error: FunctionRequiresFloatValue("RAND")

SELECT RAND(TRUE) AS rand;
-- Error: FunctionRequiresFloatValue("RAND")

SELECT RAND(FALSE) AS rand;
-- Error: FunctionRequiresFloatValue("RAND")
  1. The RAND function takes at most one argument:
SELECT RAND('string', 'string2') AS rand;
-- Error: FunctionArgsLengthNotWithinRange("RAND", 0, 1, 2)
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/math/round/index.html b/docs/0.16.0/sql-syntax/functions/math/round/index.html new file mode 100644 index 00000000..61abcb23 --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/math/round/index.html @@ -0,0 +1,17 @@ + + + + + +ROUND | GlueSQL + + + + + +
+

ROUND

The ROUND function is used to round a number to the nearest integer value. It takes a single floating-point or integer value as its argument and returns a floating-point value.

Syntax

ROUND(value)

Examples

Let's consider a table named SingleItem with the following schema:

CREATE TABLE SingleItem (id INTEGER);

Insert a row into the SingleItem table:

INSERT INTO SingleItem VALUES (0);

Example 1: Using ROUND function

SELECT ROUND(0.3) AS round1,
ROUND(-0.8) AS round2,
ROUND(10) AS round3,
ROUND(6.87421) AS round4
FROM SingleItem;

Result:

round1 | round2 | round3 | round4
-------+--------+--------+--------
0.0 | -1.0 | 10.0 | 7.0

Note that the returned values are floating-point numbers, even though they represent integer values.

Errors

The ROUND function expects a floating-point or integer value as its argument. Providing any other type, such as a string or boolean, will result in an error.

Example 2: Using ROUND with a string argument

SELECT ROUND('string') AS round FROM SingleItem;

Error: Function requires a floating-point or integer value.

Example 3: Using ROUND with a boolean argument

SELECT ROUND(TRUE) AS round FROM SingleItem;

Error: Function requires a floating-point or integer value.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/math/sign/index.html b/docs/0.16.0/sql-syntax/functions/math/sign/index.html new file mode 100644 index 00000000..d8e07f08 --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/math/sign/index.html @@ -0,0 +1,17 @@ + + + + + +SIGN | GlueSQL + + + + + +
+

SIGN

The SIGN function is used to determine the sign of a number. It takes one argument, which must be of the FLOAT type. The result will be of the INTEGER type and can be -1, 0, or 1.

Syntax

SIGN(number)

Examples

  1. Using the SIGN function with integers:
SELECT SIGN(2) AS SIGN1, 
SIGN(-2) AS SIGN2,
SIGN(+2) AS SIGN3;
-- Result: 1, -1, 1
  1. Using the SIGN function with floats:
SELECT SIGN(2.0) AS SIGN1, 
SIGN(-2.0) AS SIGN2,
SIGN(+2.0) AS SIGN3;
-- Result: 1, -1, 1
  1. Using the SIGN function with zero:
SELECT SIGN(0.0) AS SIGN1, 
SIGN(-0.0) AS SIGN2,
SIGN(+0.0) AS SIGN3;
-- Result: 0, 0, 0
  1. Using the SIGN function with NULL:
SELECT SIGN(NULL) AS sign;
-- Result: NULL

Error Cases

  1. The SIGN function requires the argument to be of FLOAT type:
SELECT SIGN('string') AS SIGN;
-- Error: FunctionRequiresFloatValue("SIGN")

SELECT SIGN(TRUE) AS sign;
-- Error: FunctionRequiresFloatValue("SIGN")

SELECT SIGN(FALSE) AS sign;
-- Error: FunctionRequiresFloatValue("SIGN")
  1. The SIGN function takes exactly one argument:
SELECT SIGN('string', 'string2') AS SIGN;
-- Error: FunctionArgsLengthNotMatching("SIGN", 1, 2)
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/math/sin/index.html b/docs/0.16.0/sql-syntax/functions/math/sin/index.html new file mode 100644 index 00000000..487de6b8 --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/math/sin/index.html @@ -0,0 +1,17 @@ + + + + + +SIN | GlueSQL + + + + + +
+

SIN

The SIN function is used to calculate the sine of a number. It takes a single numeric argument (angle in radians) and returns the sine of that angle.

Syntax

SIN(value)
  • value: A numeric expression (angle in radians) for which the sine is to be calculated.

Examples

Let's consider a table named SingleItem with the following schema:

CREATE TABLE SingleItem (id INTEGER);

Insert a row into the SingleItem table:

INSERT INTO SingleItem VALUES (0);

Example 1: Using SIN with float values

SELECT SIN(0.5) AS sin1, SIN(1) AS sin2 FROM SingleItem;

Result:

    sin1     |    sin2
-------------+--------------
0.479425539 | 0.841470984

Example 2: Using SIN with NULL values

SELECT SIN(NULL) AS sin FROM SingleItem;

Result:

  sin
-------
(null)

Errors

The SIN function requires a numeric value as its argument. Using non-numeric values or more than one argument will result in an error.

Example 3: Using SIN with non-numeric values

SELECT SIN('string') AS sin FROM SingleItem;

Error: Function requires a numeric value.

Example 4: Using SIN with multiple arguments

SELECT SIN(1.0, 2.0) AS sin FROM SingleItem;

Error: Function expects 1 argument, but 2 were provided.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/math/sqrt/index.html b/docs/0.16.0/sql-syntax/functions/math/sqrt/index.html new file mode 100644 index 00000000..9861c30e --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/math/sqrt/index.html @@ -0,0 +1,17 @@ + + + + + +SQRT | GlueSQL + + + + + +
+

SQRT

The SQRT function is used to calculate the square root of a number. It takes one argument, which must be of the FLOAT type. The result will also be of the FLOAT type.

Syntax

SQRT(number)

Examples

  1. Using the SQRT function:
SELECT SQRT(2.0) as sqrt_1;
-- Result: 1.4142135623730951
  1. Using the SQRT function with a decimal:
SELECT SQRT(0.07) as sqrt_2;
-- Result: 0.2645751311064591
  1. Using the SQRT function with an integer:
SELECT SQRT(32) as sqrt_with_int;
-- Result: 5.656854249492381
  1. Using the SQRT function with zero:
SELECT SQRT(0) as sqrt_with_zero;
-- Result: 0.0
  1. Using the SQRT function with NULL:
SELECT SQRT(NULL) AS sqrt;
-- Result: NULL

Error Cases

  1. The SQRT function requires the argument to be of FLOAT type:
SELECT SQRT('string') AS sqrt;
-- Error: SqrtOnNonNumeric("string")
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/math/tan/index.html b/docs/0.16.0/sql-syntax/functions/math/tan/index.html new file mode 100644 index 00000000..83b9f713 --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/math/tan/index.html @@ -0,0 +1,17 @@ + + + + + +TAN | GlueSQL + + + + + +
+

TAN

The TAN function is used to calculate the tangent of a number. It takes a single numeric argument (angle in radians) and returns the tangent of that angle.

Syntax

TAN(value)
  • value: A numeric expression (angle in radians) for which the tangent is to be calculated.

Examples

Let's consider a table named SingleItem with the following schema:

CREATE TABLE SingleItem (id INTEGER);

Insert a row into the SingleItem table:

INSERT INTO SingleItem VALUES (0);

Example 1: Using TAN with float values

SELECT TAN(0.5) AS tan1, TAN(1) AS tan2 FROM SingleItem;

Result:

    tan1    |    tan2
------------+---------------
0.54630249 | 1.557407725

Example 2: Using TAN with NULL values

SELECT TAN(NULL) AS tan FROM SingleItem;

Result:

  tan
-------
(null)

Errors

The TAN function requires a numeric value as its argument. Using non-numeric values or more than one argument will result in an error.

Example 3: Using TAN with non-numeric values

SELECT TAN('string') AS tan FROM SingleItem;

Error: Function requires a numeric value.

Example 4: Using TAN with multiple arguments

SELECT TAN(1.0, 2.0) AS tan FROM SingleItem;

Error: Function expects 1 argument, but 2 were provided.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/others/cast/index.html b/docs/0.16.0/sql-syntax/functions/others/cast/index.html new file mode 100644 index 00000000..2262d65f --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/others/cast/index.html @@ -0,0 +1,17 @@ + + + + + +CAST | GlueSQL + + + + + +
+

CAST

The CAST function is used to convert a value from one data type to another. It is commonly used when you need to change the data type of a value or a column to perform a specific operation, such as arithmetic or string concatenation.

Syntax

CAST(expression AS data_type)
  • expression: The value or column you want to convert.
  • data_type: The target data type to which you want to convert the expression.

Examples

Converting a value to a different data type

SELECT CAST('TRUE' AS BOOLEAN) AS cast;

In this example, the CAST function is used to convert the string 'TRUE' to a boolean value.

Converting a column to a different data type

Suppose you have a table called employees with the following structure:

CREATE TABLE employees (id INT, name TEXT, salary TEXT);

To calculate the total salary of all employees, you can use the CAST function to convert the salary column to a DECIMAL data type:

SELECT SUM(CAST(salary AS DECIMAL)) AS total_salary FROM employees;

Handling NULL values

The CAST function can handle NULL values as well. If the expression is NULL, the result will be NULL:

SELECT CAST(NULL AS INTEGER) AS cast;

This query will return a NULL value.

Converting a value to a DATE or TIME data type

The CAST function can also be used to convert strings to DATE or TIME data types:

SELECT CAST('2023-05-04' AS DATE) AS cast_date;
SELECT CAST('14:30:00' AS TIME) AS cast_time;

These queries will return a date and time value, respectively.

Limitations and Errors

Some conversions may be impossible or result in an error. For example, trying to convert a non-numeric string to an integer will result in an error:

SELECT CAST('foo' AS INTEGER) AS cast;

This query will produce an error because the string 'foo' cannot be converted to an integer.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/others/generate-uuid/index.html b/docs/0.16.0/sql-syntax/functions/others/generate-uuid/index.html new file mode 100644 index 00000000..c3c7449f --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/others/generate-uuid/index.html @@ -0,0 +1,17 @@ + + + + + +GENERATE_UUID | GlueSQL + + + + + +
+

GENERATE_UUID

The GENERATE_UUID function is an SQL function provided by GlueSQL that generates a new UUID (Universally Unique Identifier) using the version 4 UUID algorithm. A UUID is a 128-bit value used to uniquely identify items in various computing systems. Version 4 UUIDs are randomly generated and have 122 bits of randomness, which ensures a very low probability of collisions.

Syntax

GENERATE_UUID()

Usage

Creating a table with a UUID column

You can use the GENERATE_UUID function as the default value for a UUID column in a table.

CREATE TABLE SingleItem (id UUID DEFAULT GENERATE_UUID());

This SQL statement creates a table called SingleItem with a column named id of data type UUID. The default value for the id column is generated using the GENERATE_UUID function.

Inserting data with a UUID column

You can also use the GENERATE_UUID function directly when inserting data into a table.

INSERT INTO SingleItem VALUES (GENERATE_UUID());

This SQL statement inserts a new row into the SingleItem table with a UUID value generated using the GENERATE_UUID function.

Selecting data with a UUID column

You can use the GENERATE_UUID function in a SELECT statement to generate UUIDs on the fly.

SELECT GENERATE_UUID() as uuid FROM SingleItem;

This SQL statement selects a new UUID for each row in the SingleItem table.

Error Handling

The GENERATE_UUID function does not accept any arguments. If you provide any arguments to the function, an error will be raised.

SELECT generate_uuid(0) as uuid FROM SingleItem;

This SQL statement will result in an error, as the GENERATE_UUID function does not accept any arguments.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/others/ifnull/index.html b/docs/0.16.0/sql-syntax/functions/others/ifnull/index.html new file mode 100644 index 00000000..b41d84a3 --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/others/ifnull/index.html @@ -0,0 +1,17 @@ + + + + + +IFNULL | GlueSQL + + + + + +
+

IFNULL

The IFNULL function is used to return the first non-null value among the provided expressions. It takes two arguments and checks if the first argument is NULL. If the first argument is NULL, it returns the second argument; otherwise, it returns the first argument.

Syntax

IFNULL(expression1, expression2)

Examples

Consider the following SingleItem table:

CREATE TABLE SingleItem (
id INTEGER NULL,
int8 INT8 NULL,
dec DECIMAL NULL,
dt DATE NULL,
mystring TEXT NULL,
mybool BOOLEAN NULL,
myfloat FLOAT NULL,
mytime TIME NULL,
mytimestamp TIMESTAMP NULL
);

Insert two records into the SingleItem table:

INSERT INTO SingleItem VALUES (0, 1, 2, '2022-05-23', 'this is a string', true, 3.15, '01:02:03', '1970-01-01 00:00:00 -00:00');
INSERT INTO SingleItem VALUES (null, null, null, null, null, null, null, null, null);

Example 1: Using IFNULL with integer values:

SELECT IFNULL(id, 1) AS myid, IFNULL(int8, 2) AS int8, IFNULL(dec, 3)
FROM SingleItem WHERE id IS NOT NULL;

Example 2: Using IFNULL with date and text values:

SELECT IFNULL(dt, '2000-01-01') AS mydate, IFNULL(mystring, 'blah') AS name
FROM SingleItem WHERE id IS NOT NULL;

Example 3: Using IFNULL with boolean and float values:

SELECT IFNULL(mybool, 'YES') AS mybool, IFNULL(myfloat, 'NO') AS myfloat
FROM SingleItem WHERE id IS NOT NULL;

Example 4: Using IFNULL with time and timestamp values:

SELECT IFNULL(mytime, 'YES') AS mybool, IFNULL(mytimestamp, 'NO') AS myfloat
FROM SingleItem WHERE id IS NOT NULL;
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/text/ascii/index.html b/docs/0.16.0/sql-syntax/functions/text/ascii/index.html new file mode 100644 index 00000000..ce570efa --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/text/ascii/index.html @@ -0,0 +1,17 @@ + + + + + +ASCII | GlueSQL + + + + + +
+

ASCII

The ASCII function in SQL returns the ASCII value for the first character of the specified string.

Syntax

The syntax for the ASCII function in SQL is:

ASCII ( single_character_text )

Parameters

  • single_character_text: This is the string that the ASCII value should be returned for. It should be a single character string.

Examples

Let's consider a few examples to understand how to use the ASCII function.

To get the ASCII value of a character:

VALUES(ASCII('A'));

This will return 65, which is the ASCII value for 'A'.

Please note that the ASCII function expects a single character value. If a string with more than one character is passed, it will throw an error. For instance:

VALUES(ASCII('AB'));

This will throw an error because 'AB' contains more than one character.

You can also use the ASCII function in a SELECT statement. Consider the following table named 'Ascii':

idtext
1'F'
CREATE TABLE Ascii (
id INTEGER,
text TEXT
);
INSERT INTO Ascii VALUES (1, 'F');

You can select the ASCII value of the 'text' column:

SELECT ASCII(text) AS ascii FROM Ascii;

This will return 70, which is the ASCII value for 'F'.

The ASCII function can also take a string directly:

SELECT ASCII('a') AS ascii FROM Ascii;

This will return 97, which is the ASCII value for 'a'.

If a non-ASCII character is passed to the function, it will throw an error. For instance:

SELECT ASCII('ㄱ') AS ascii FROM Ascii;

This will throw an error because 'ㄱ' is not an ASCII character.

If no argument is passed to the ASCII function, it will also throw an error:

SELECT ASCII() AS ascii FROM Ascii;

This will throw an error because the ASCII function expects one argument.

Remember, the ASCII function expects a single character. If the column value contains more than one character, it will throw an error:

INSERT INTO Ascii VALUES (1, 'Foo');
SELECT ASCII(text) AS ascii FROM Ascii;

This will throw an error because 'Foo' contains more than one character.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/text/chr/index.html b/docs/0.16.0/sql-syntax/functions/text/chr/index.html new file mode 100644 index 00000000..528f8996 --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/text/chr/index.html @@ -0,0 +1,17 @@ + + + + + +CHR | GlueSQL + + + + + +
+

CHR

The CHR function in SQL returns the character represented by the specified ASCII value.

Syntax

The syntax for the CHR function in SQL is:

CHR ( ascii_value )

Parameters

  • ascii_value: This is the ASCII value for which the character should be returned. It should be an integer value between 0 and 255.

Examples

Let's consider a few examples to understand how to use the CHR function.

To get the character for an ASCII value:

VALUES(CHR(70));

This will return 'F', which is the character for the ASCII value 70.

Please note that the CHR function expects an integer value between 0 and 255. If a value outside this range is passed, it will throw an error. For instance:

VALUES(CHR(7070));

This will throw an error because 7070 is not a valid ASCII value.

You can also use the CHR function in a SELECT statement. Consider the following table named 'Chr':

idnum
170
CREATE TABLE Chr (
id INTEGER,
num INTEGER
);
INSERT INTO Chr VALUES (1, 70);

You can select the character for the 'num' column:

SELECT CHR(num) AS chr FROM Chr;

This will return 'F', which is the character for the ASCII value 70.

The CHR function can also take an integer value directly:

SELECT CHR(65) AS chr FROM Chr;

This will return 'A', which is the character for the ASCII value 65.

If a non-integer value is passed to the function, it will throw an error. For instance:

SELECT CHR('ukjhg') AS chr FROM Chr;

This will throw an error because 'ukjhg' is not an integer value.

Remember, the CHR function expects an integer value between 0 and 255. If the column value is outside this range, it will throw an error:

INSERT INTO Chr VALUES (1, 4345);
SELECT CHR(num) AS chr FROM Chr;

This will throw an error because 4345 is not a valid ASCII value.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/text/concat-ws/index.html b/docs/0.16.0/sql-syntax/functions/text/concat-ws/index.html new file mode 100644 index 00000000..b1711c8b --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/text/concat-ws/index.html @@ -0,0 +1,17 @@ + + + + + +CONCAT_WS | GlueSQL + + + + + +
+

CONCAT_WS

The CONCAT_WS function in SQL concatenates two or more strings into one string with a separator.

Syntax

The syntax for the CONCAT_WS function in SQL is:

CONCAT_WS ( separator, string1, string2, ..., stringN )

Parameters

  • separator: This is the string that will be placed between each string to be concatenated.
  • string1, string2, ..., stringN: These are the strings that you wish to concatenate together.

Examples

Let's consider a few examples to understand how to use the CONCAT_WS function.

To concatenate strings with a comma separator:

VALUES(CONCAT_WS(',', 'AB', 'CD', 'EF'));

This will return 'AB,CD,EF'.

You can also concatenate more than two strings:

SELECT CONCAT_WS('/', 'ab', 'cd', 'ef') AS myconcat;

This will return 'ab/cd/ef'.

The CONCAT_WS function will skip any NULL values:

SELECT CONCAT_WS('', 'ab', 'cd', NULL, 'ef') AS myconcat;

This will return 'abcdef'.

The CONCAT_WS function can also take non-string arguments:

SELECT CONCAT_WS('', 123, 456, 3.14) AS myconcat;

This will return '1234563.14'. In this case, the integers and float values are implicitly converted to strings before concatenation.

However, the CONCAT_WS function expects at least two arguments. If fewer than two arguments are passed to the CONCAT_WS function, it will throw an error:

SELECT CONCAT_WS() AS myconcat;

This will throw an error because the CONCAT_WS function expects at least two arguments.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/text/concat/index.html b/docs/0.16.0/sql-syntax/functions/text/concat/index.html new file mode 100644 index 00000000..3a392976 --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/text/concat/index.html @@ -0,0 +1,17 @@ + + + + + +CONCAT | GlueSQL + + + + + +
+

CONCAT

The CONCAT function in SQL concatenates two or more strings into one string.

Syntax

The syntax for the CONCAT function in SQL is:

CONCAT ( string1, string2, ..., stringN )

Parameters

  • string1, string2, ..., stringN: These are the strings that you wish to concatenate together.

Examples

Let's consider a few examples to understand how to use the CONCAT function.

To concatenate two strings:

SELECT CONCAT('ab', 'cd') AS myconcat;

This will return 'abcd'.

You can also concatenate more than two strings:

SELECT CONCAT('ab', 'cd', 'ef') AS myconcat;

This will return 'abcdef'.

If any string in the CONCAT function is NULL, the function will return NULL:

SELECT CONCAT('ab', 'cd', NULL, 'ef') AS myconcat;

This will return NULL.

The CONCAT function can also take non-string arguments:

SELECT CONCAT(123, 456, 3.14) AS myconcat;

This will return '1234563.14'. In this case, the integers and float values are implicitly converted to strings before concatenation.

However, the CONCAT function expects at least one argument. If no arguments are passed to the CONCAT function, it will throw an error:

SELECT CONCAT() AS myconcat;

This will throw an error because the CONCAT function expects at least one argument.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/text/find-idx/index.html b/docs/0.16.0/sql-syntax/functions/text/find-idx/index.html new file mode 100644 index 00000000..d30c8866 --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/text/find-idx/index.html @@ -0,0 +1,17 @@ + + + + + +FIND_IDX | GlueSQL + + + + + +
+

FIND_IDX

The FIND_IDX function in SQL is used to return the position of the first occurrence of a substring in a string, optionally after a specified position.

Syntax

The syntax for the FIND_IDX function in SQL is:

FIND_IDX ( string, substring, [ start_position ] )

Parameters

  • string: The string where the search will take place.
  • substring: The substring to find.
  • start_position (optional): The position at which to start the search. The first position in the string is 0. If the start_position is not specified, the search starts from the beginning of the string.

Examples

Let's consider a few examples to understand how to use the FIND_IDX function.

Find the position of 'rg' in 'pork':

SELECT FIND_IDX('pork', 'rg') AS test;

This will return 0, as 'rg' is not found in 'pork'.

Find the position of 'rg' in 'burger':

SELECT FIND_IDX('burger', 'rg') AS test;

This will return 3, as the first occurrence of 'rg' in 'burger' is at position 3.

Find the position of 'r' in 'pork', starting from position 4:

SELECT FIND_IDX('pork', 'r', 4) AS test;

This will return 0, as 'r' is not found in 'pork' after position 4.

Find the position of 'r' in 'burger', starting from position 4:

SELECT FIND_IDX('burger', 'r', 4) AS test;

This will return 6, as the first occurrence of 'r' in 'burger' after position 4 is at position 6.

Find the position of an empty string in 'cheese':

SELECT FIND_IDX('cheese', '') AS test;

This will return 0, because the search starts at the first position by default and the empty string is considered to be found at the start of any string.

Find the position of 's' in 'cheese':

SELECT FIND_IDX('cheese', 's') AS test;

This will return 5, as the first occurrence of 's' in 'cheese' is at position 5.

Find the position of 'e' in 'cheese burger', starting from position 5:

SELECT FIND_IDX('cheese burger', 'e', 5) AS test;

This will return 6, because the search starts from position 5 and the next 'e' is at position 6.

Using a NULL value as the substring will return NULL:

SELECT FIND_IDX('cheese', NULL) AS test;
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/text/initcap/index.html b/docs/0.16.0/sql-syntax/functions/text/initcap/index.html new file mode 100644 index 00000000..77f32ead --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/text/initcap/index.html @@ -0,0 +1,17 @@ + + + + + +INITCAP | GlueSQL + + + + + +
+

INITCAP

The INITCAP function in SQL is used to capitalize the first letter of each word in a string and convert the rest of the characters to lowercase.

Syntax

The syntax for the INITCAP function in SQL is:

INITCAP( string )

Parameters

  • string: The input string on which the capitalization will be applied.

Examples

Let's consider a few examples to understand how to use the INITCAP function.

Create a table named Item with a column name:

CREATE TABLE Item (
name TEXT DEFAULT 'abcd',
);

Insert some data into the Item table:

INSERT INTO Item VALUES
('h/i jk'),
(NULL),
('H/I JK');

Select rows where the INITCAP(name) is equal to 'H/I Jk':

SELECT name FROM Item WHERE INITCAP(name) = 'H/I Jk';

This will return the rows with 'h/i jk' and 'H/I JK', as both have the same result after applying the INITCAP function.

Apply the INITCAP function to the name column and return the result:

SELECT INITCAP(name) FROM Item;

This will return 'H/I Jk', NULL, and 'H/I Jk' for the three rows, respectively.

The INITCAP function expects a string value as the input. If a non-string value is passed as the input, it will throw an error:

SELECT INITCAP(1) FROM Item;

This will throw an error because the INITCAP function expects a string value as the input.

The INITCAP function expects a single argument. If no arguments are provided, it will throw an error:

SELECT INITCAP() FROM Item;

This will throw an error because the INITCAP function expects a single argument.

The INITCAP function does not support named arguments. If a named argument is provided, it will throw an error:

SELECT INITCAP(a => 2) FROM Item;

This will throw an error because the INITCAP function does not support named arguments.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/text/left/index.html b/docs/0.16.0/sql-syntax/functions/text/left/index.html new file mode 100644 index 00000000..f475be56 --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/text/left/index.html @@ -0,0 +1,17 @@ + + + + + +LEFT | GlueSQL + + + + + +
+

LEFT

The LEFT function in SQL returns the specified number of characters from the start (left side) of a given string.

Syntax

LEFT(string, number)

Parameters

  • string: The original string from which to extract characters.
  • number: The number of characters to extract from the start of the string. This must be an integer.

Return Value

The function returns a string, which consists of the specified number of characters from the start of the original string. If the original string is shorter than the specified number, the function returns the whole string.

Errors

  • If the number argument is not an integer, a FunctionRequiresIntegerValue error will be returned.
  • If the string argument is not a string, a FunctionRequiresStringValue error will be returned.

Examples

Consider a table Item created and filled with the following data:

CREATE TABLE Item (
name TEXT DEFAULT LEFT('abc', 1)
);
INSERT INTO Item VALUES ('Blop mc blee'), ('B'), ('Steven the &long named$ folken!');

You can use the LEFT function to extract the first three characters of each name:

SELECT LEFT(name, 3) AS test FROM Item;

This will return:

Blo
B
Ste

Note that when the string length is less than the specified number (as with 'B'), the function will return the whole string.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/text/lower/index.html b/docs/0.16.0/sql-syntax/functions/text/lower/index.html new file mode 100644 index 00000000..9a32dbf9 --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/text/lower/index.html @@ -0,0 +1,17 @@ + + + + + +LOWER | GlueSQL + + + + + +
+

LOWER

The LOWER function in SQL returns a string in which all alphabetic characters in a specified string are converted to lowercase.

Syntax

LOWER(string)

Parameters

  • string: The original string to convert.

Return Value

The function returns a new string that is the same as the original string, but with all uppercase characters converted to lowercase. Non-alphabetic characters in the string are unaffected.

Errors

  • If the string argument is not a string, a FunctionRequiresStringValue error will be returned.

Examples

Consider a table Item created and filled with the following data:

CREATE TABLE Item (
name TEXT
);
INSERT INTO Item VALUES ('ABCD'), ('Abcd'), ('abcd');

You can use the LOWER function to convert all name values to lowercase:

SELECT LOWER(name) AS lower_name FROM Item;

This will return:

abcd
abcd
abcd

Note that the LOWER function affects only alphabetic characters. Non-alphabetic characters in the string remain unchanged.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/text/lpad/index.html b/docs/0.16.0/sql-syntax/functions/text/lpad/index.html new file mode 100644 index 00000000..41215a54 --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/text/lpad/index.html @@ -0,0 +1,17 @@ + + + + + +LPAD | GlueSQL + + + + + +
+

LPAD

The LPAD function in SQL pads the left side of a string with a specific set of characters.

Syntax

LPAD(string, length, pad_string)

Parameters

  • string: The original string to pad.
  • length: The length of the resulting string after padding. If this is less than the length of the original string, the result is truncated.
  • pad_string (optional): The string to use for padding. If not supplied, spaces are used.

Return Value

The function returns a new string that is the same as the original string, but with additional padding on the left side to achieve the specified length.

Errors

  • If the string argument is not a string, a FunctionRequiresStringValue error will be returned.
  • If the length argument is not a positive integer, a FunctionRequiresUSizeValue error will be returned.

Examples

Consider a table Item created and filled with the following data:

CREATE TABLE Item (
name TEXT
);
INSERT INTO Item VALUES ('hello');

You can use the LPAD function to pad the name values to a length of 10 with the character 'a':

SELECT LPAD(name, 10, 'a') AS padded_name FROM Item;

This will return:

aaaaahello

If the length argument is less than the length of the string, the original string will be truncated:

SELECT LPAD(name, 3, 'a') AS padded_name FROM Item;

This will return:

hel
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/text/ltrim/index.html b/docs/0.16.0/sql-syntax/functions/text/ltrim/index.html new file mode 100644 index 00000000..f948ed60 --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/text/ltrim/index.html @@ -0,0 +1,17 @@ + + + + + +LTRIM | GlueSQL + + + + + +
+

LTRIM

The LTRIM function in SQL removes characters from the left (leading side) of a string.

Syntax

LTRIM(string, trim_string)

Parameters

  • string: The original string to trim.
  • trim_string (optional): The characters to remove from the string. If not supplied, spaces are removed.

Return Value

The function returns a new string that is the same as the original string, but without the specified leading characters.

Errors

  • If the string or trim_string argument is not a string, a FunctionRequiresStringValue error will be returned.

Examples

Consider a table Item created and filled with the following data:

CREATE TABLE Item (
name TEXT
);
INSERT INTO Item VALUES (' zzzytest');

You can use the LTRIM function to remove leading spaces from the name values:

SELECT LTRIM(name) AS trimmed_name FROM Item;

This will return:

zzzytest

You can also specify a string of characters to remove. The function will remove any character in this string from the start of the original string:

SELECT LTRIM(name, ' z') AS trimmed_name FROM Item;

This will return:

ytest
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/text/position/index.html b/docs/0.16.0/sql-syntax/functions/text/position/index.html new file mode 100644 index 00000000..657bee7d --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/text/position/index.html @@ -0,0 +1,17 @@ + + + + + +POSITION | GlueSQL + + + + + +
+

POSITION

The POSITION function in SQL is used to find the position of a substring in a string. The position of the first occurrence of the substring is returned. If the substring is not found, this function returns 0.

Syntax

POSITION(substring IN string)

Parameters

  • substring: The substring to search for.
  • string: The string in which to search.

Return Value

The function returns an integer representing the position of the first occurrence of the substring in the string, starting from 1. If the substring is not found, the function returns 0.

Errors

  • If either substring or string are not string values, a ValueError::NonStringParameterInPosition error will be returned.

Examples

Consider a table Food created and filled with the following data:

CREATE TABLE Food (
name TEXT
);
INSERT INTO Food VALUES ('pork');
INSERT INTO Food VALUES ('burger');

You can use the POSITION function to find the position of a substring within the name values:

SELECT POSITION('e' IN name) AS test FROM Food;

This will return:

0
5

The first 'e' in 'burger' is at position 5, so the function returns 5 for 'burger'. There is no 'e' in 'pork', so the function returns 0 for 'pork'.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/text/repeat/index.html b/docs/0.16.0/sql-syntax/functions/text/repeat/index.html new file mode 100644 index 00000000..3a5dec52 --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/text/repeat/index.html @@ -0,0 +1,17 @@ + + + + + +REPEAT | GlueSQL + + + + + +
+

REPEAT

The REPEAT function in SQL is used to repeat a string for a specified number of times.

Syntax

REPEAT(string, number)

Parameters

  • string: The string to be repeated.
  • number: The number of times to repeat the string.

Return Value

The function returns a string which is the concatenation of the input string repeated the specified number of times.

Errors

  • If the parameters are not in the correct format, a TranslateError::FunctionArgsLengthNotMatching error will be returned. This function requires exactly two arguments.
  • If either string or number are not string values, a EvaluateError::FunctionRequiresStringValue error will be returned.

Examples

Consider a table Item created and filled with the following data:

CREATE TABLE Item (name TEXT);
INSERT INTO Item VALUES ('hello');

You can use the REPEAT function to repeat the name values:

SELECT REPEAT(name, 2) AS test FROM Item;

This will return:

hellohello

The 'hello' string is repeated twice as specified by the second parameter to the REPEAT function.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/text/reverse/index.html b/docs/0.16.0/sql-syntax/functions/text/reverse/index.html new file mode 100644 index 00000000..66e38343 --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/text/reverse/index.html @@ -0,0 +1,17 @@ + + + + + +REVERSE | GlueSQL + + + + + +
+

REVERSE

The REVERSE function in SQL is used to reverse a string.

Syntax

REVERSE(string)

Parameters

  • string: The string to be reversed.

Return Value

The function returns a string which is the reverse of the input string.

Errors

If the parameter is not a string value, a EvaluateError::FunctionRequiresStringValue error will be returned.

Examples

Consider a table Item created and filled with the following data:

CREATE TABLE Item (name TEXT);
INSERT INTO Item VALUES ('Let''s meet');

You can use the REVERSE function to reverse the name values:

SELECT REVERSE(name) AS test FROM Item;

This will return:

teem s'teL

The 'Let''s meet' string is reversed as 'teem s'teL'.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/text/right/index.html b/docs/0.16.0/sql-syntax/functions/text/right/index.html new file mode 100644 index 00000000..8730e0cd --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/text/right/index.html @@ -0,0 +1,17 @@ + + + + + +RIGHT | GlueSQL + + + + + +
+

RIGHT

The RIGHT function in SQL returns the specified number of characters from the end (right side) of a given string.

Syntax

RIGHT(string, number)

Parameters

  • string: The original string from which to extract characters.
  • number: The number of characters to extract from the end of the string. This must be an integer.

Return Value

The function returns a string, which consists of the specified number of characters from the end of the original string. If the original string is shorter than the specified number, the function returns the whole string.

Errors

  • If the number argument is not an integer, a FunctionRequiresIntegerValue error will be returned.
  • If the string argument is not a string, a FunctionRequiresStringValue error will be returned.
  • If the number argument is negative, a FunctionRequiresUSizeValue error will be returned.

Examples

Consider a table Item created and filled with the following data:

CREATE TABLE Item (
name TEXT
);
INSERT INTO Item VALUES ('Blop mc blee'), ('B'), ('Steven the &long named$ folken!');

You can use the RIGHT function to extract the last three characters of each name:

SELECT RIGHT(name, 3) AS test FROM Item;

This will return:

lee
B
en!

Note that when the string length is less than the specified number (as with 'B'), the function will return the whole string.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/text/rpad/index.html b/docs/0.16.0/sql-syntax/functions/text/rpad/index.html new file mode 100644 index 00000000..1b6390c0 --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/text/rpad/index.html @@ -0,0 +1,17 @@ + + + + + +RPAD | GlueSQL + + + + + +
+

RPAD

The RPAD function in SQL pads the right side of a string with a specific set of characters.

Syntax

RPAD(string, length, pad_string)

Parameters

  • string: The original string to pad.
  • length: The length of the resulting string after padding. If this is less than the length of the original string, the result is truncated.
  • pad_string (optional): The string to use for padding. If not supplied, spaces are used.

Return Value

The function returns a new string that is the same as the original string, but with additional padding on the right side to achieve the specified length.

Errors

  • If the string argument is not a string, a FunctionRequiresStringValue error will be returned.
  • If the length argument is not a positive integer, a FunctionRequiresUSizeValue error will be returned.

Examples

Consider a table Item created and filled with the following data:

CREATE TABLE Item (
name TEXT
);
INSERT INTO Item VALUES ('hello');

You can use the RPAD function to pad the name values to a length of 10 with the character 'b':

SELECT RPAD(name, 10, 'b') AS padded_name FROM Item;

This will return:

hellobbbbb

If the length argument is less than the length of the string, the original string will be truncated:

SELECT RPAD(name, 3, 'b') AS padded_name FROM Item;

This will return:

hel
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/text/rtrim/index.html b/docs/0.16.0/sql-syntax/functions/text/rtrim/index.html new file mode 100644 index 00000000..70ad74bf --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/text/rtrim/index.html @@ -0,0 +1,17 @@ + + + + + +RTRIM | GlueSQL + + + + + +
+

RTRIM

The RTRIM function in SQL removes characters from the right (trailing side) of a string.

Syntax

RTRIM(string, trim_string)

Parameters

  • string: The original string to trim.
  • trim_string (optional): The characters to remove from the string. If not supplied, spaces are removed.

Return Value

The function returns a new string that is the same as the original string, but without the specified trailing characters.

Errors

  • If the string or trim_string argument is not a string, a FunctionRequiresStringValue error will be returned.

Examples

Consider a table Item created and filled with the following data:

CREATE TABLE Item (
name TEXT
);
INSERT INTO Item VALUES ('testxxzx ');

You can use the RTRIM function to remove trailing spaces from the name values:

SELECT RTRIM(name) AS trimmed_name FROM Item;

This will return:

testxxzx

You can also specify a string of characters to remove. The function will remove any character in this string from the end of the original string:

SELECT RTRIM(name, 'zx ') AS trimmed_name FROM Item;

This will return:

test
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/text/substr/index.html b/docs/0.16.0/sql-syntax/functions/text/substr/index.html new file mode 100644 index 00000000..f9856a86 --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/text/substr/index.html @@ -0,0 +1,17 @@ + + + + + +SUBSTR | GlueSQL + + + + + +
+

SUBSTR

The SUBSTR function in SQL is used to extract a substring from a string.

Syntax

SUBSTR(string, start_position, length)

Parameters

  • string: The original string.
  • start_position: The position in the string where the extraction of the substring will begin. The position of the first character is 1. If start_position is 0 or negative, the function treats it as 1.
  • length (optional): The number of characters to extract. If length is not included, the function will return all characters starting from start_position.

Return Value

The function returns a string which is a substring of the original string. The substring starts at start_position and has length number of characters.

Errors

  • If the string parameter is not a string value, a EvaluateError::FunctionRequiresStringValue error will be returned.
  • If the start_position or length parameters are not integer values, a EvaluateError::FunctionRequiresIntegerValue error will be returned.
  • If the length parameter is negative, a EvaluateError::NegativeSubstrLenNotAllowed error will be returned.

Examples

Consider a table Item created and filled with the following data:

CREATE TABLE Item (name TEXT);
INSERT INTO Item VALUES ('Blop mc blee'), ('B'), ('Steven the &long named$ folken!');

You can use the SUBSTR function to get a substring from the name values:

SELECT SUBSTR(name, 2) AS test FROM Item;

This will return:

lop mc blee
(empty string)
teven the &long named$ folken!

The function takes the substring starting from the second character until the end for each name value.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/text/trim/index.html b/docs/0.16.0/sql-syntax/functions/text/trim/index.html new file mode 100644 index 00000000..aa136612 --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/text/trim/index.html @@ -0,0 +1,17 @@ + + + + + +TRIM | GlueSQL + + + + + +
+

TRIM

The TRIM function in SQL is used to remove leading, trailing, or both leading and trailing unwanted characters (often whitespace) from a string.

Syntax

TRIM([LEADING | TRAILING | BOTH] [removal_string] FROM target_string)

If LEADING, TRAILING, or BOTH is not specified, TRIM function will remove both leading and trailing spaces.

Examples

Here we are creating a table named Item with a default value for the name column. The default value is obtained by concatenating two strings. The first string is the result of trimming leading 'a' from 'aabc' and the second string is the result of trimming spaces from ' good '.

CREATE TABLE Item (
name TEXT DEFAULT TRIM(LEADING 'a' FROM 'aabc') || TRIM(' good ')
)

We insert some data into the Item table:

INSERT INTO Item VALUES
(' Left blank'),
('Right blank '),
(' Blank! '),
('Not Blank');

The TRIM function is used in a SELECT statement to remove leading and trailing spaces from the name column in the Item table:

SELECT TRIM(name) FROM Item;

The TRIM function can also be used with NULL values. If the value is NULL, the TRIM function will return NULL.

CREATE TABLE NullName (name TEXT NULL);
INSERT INTO NullName VALUES (NULL);
SELECT TRIM(name) AS test FROM NullName;

You can also specify a specific character to remove from the string. The following example removes 'xyz' from the string:

CREATE TABLE Test (name TEXT);
INSERT INTO Test VALUES
(' blank '),
('xxxyzblankxyzxx'),
('xxxyzblank '),
(' blankxyzxx'),
(' xyzblankxyzxx'),
('xxxyzblankxyz ');
SELECT TRIM(BOTH 'xyz' FROM name) FROM Test;

The LEADING and TRAILING keywords can be used to remove characters from the beginning or the end of the string, respectively:

SELECT TRIM(LEADING 'xyz' FROM name) FROM Test;
SELECT TRIM(TRAILING 'xyz' FROM name) FROM Test;

You can also nest TRIM functions:

SELECT TRIM(BOTH TRIM(BOTH ' potato ')) AS Case1;

The TRIM function requires string values. If you try to use it with a non-string value, an error will occur:

SELECT TRIM('1' FROM 1) AS test FROM Test;
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/functions/text/upper/index.html b/docs/0.16.0/sql-syntax/functions/text/upper/index.html new file mode 100644 index 00000000..8f17432f --- /dev/null +++ b/docs/0.16.0/sql-syntax/functions/text/upper/index.html @@ -0,0 +1,17 @@ + + + + + +UPPER | GlueSQL + + + + + +
+

UPPER

The UPPER function in SQL converts all lowercase alphabetic characters in a specified string to uppercase.

Syntax

UPPER(string)

Parameters

  • string: The original string to convert.

Return Value

The function returns a new string that is the same as the original string, but with all lowercase characters converted to uppercase. Non-alphabetic characters in the string are unaffected.

Errors

  • If the string argument is not a string, a FunctionRequiresStringValue error will be returned.

Examples

Consider a table Item created and filled with the following data:

CREATE TABLE Item (
name TEXT
);
INSERT INTO Item VALUES ('abcd'), ('Abcd'), ('ABCD');

You can use the UPPER function to convert all name values to uppercase:

SELECT UPPER(name) AS upper_name FROM Item;

This will return:

ABCD
ABCD
ABCD

Note that the UPPER function affects only alphabetic characters. Non-alphabetic characters in the string remain unchanged.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/intro/index.html b/docs/0.16.0/sql-syntax/intro/index.html new file mode 100644 index 00000000..9dffb979 --- /dev/null +++ b/docs/0.16.0/sql-syntax/intro/index.html @@ -0,0 +1,18 @@ + + + + + +Introduction | GlueSQL + + + + + +
+

SQL Syntax

Welcome to the Introduction page for the SQL Syntax category in GlueSQL! In this section, we'll provide a brief overview of the SQL syntax supported by GlueSQL. You can find more in-depth examples and details by browsing the other pages in this category.

GlueSQL is a SQL database engine written in Rust, designed to be lightweight, fast, and easy to integrate with various data storage systems. It supports a wide range of SQL features, including creating and managing tables, inserting and updating data, and performing various types of queries.

Here's a list of some basic SQL statements you can use with GlueSQL:

Creating Tables

CREATE TABLE table_name (
column_name1 data_type1,
column_name2 data_type2,
...
);

Inserting Data

INSERT INTO table_name (column1, column2, ...) VALUES (value1, value2, ...);

Selecting Data

SELECT column1, column2, ... FROM table_name WHERE conditions;

Updating Data

UPDATE table_name SET column1 = value1, column2 = value2, ... WHERE conditions;

Deleting Data

DELETE FROM table_name WHERE conditions;

For a complete list of supported SQL features, you can visit the GlueSQL GitHub repository's test suite folder, even if you're not familiar with Rust code: +https://github.com/gluesql/gluesql/tree/main/test-suite/src

This folder contains tests for all the functionalities supported by GlueSQL, providing you with an extensive reference for syntax and usage.

Feel free to explore the other pages in this category to dive deeper into GlueSQL's SQL syntax and capabilities!

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/statements/data-definition/alter-table/index.html b/docs/0.16.0/sql-syntax/statements/data-definition/alter-table/index.html new file mode 100644 index 00000000..e9c6b6c4 --- /dev/null +++ b/docs/0.16.0/sql-syntax/statements/data-definition/alter-table/index.html @@ -0,0 +1,17 @@ + + + + + +ALTER TABLE | GlueSQL + + + + + +
+

ALTER TABLE

The ALTER TABLE statement is an SQL command used to modify the structure of an existing table in a database. This operation is useful when you need to add, remove, or modify columns or constraints in a table. In this document, we'll explain the syntax and usage of the ALTER TABLE statement, including the RENAME, ADD COLUMN, and DROP COLUMN clauses.

Syntax

The basic syntax for the ALTER TABLE statement is as follows:

ALTER TABLE table_name action;
  • table_name: The name of the table you want to alter.
  • action: The action you want to perform on the table, such as renaming the table, adding a new column, or dropping an existing column.

RENAME

To rename a table or a column, use the following syntax:

ALTER TABLE table_name RENAME [TO new_table_name | COLUMN column_name TO new_column_name];

ADD COLUMN

To add a new column to a table, use the following syntax:

ALTER TABLE table_name ADD COLUMN column_name datatype [DEFAULT default_value] [NOT NULL] [UNIQUE];

DROP COLUMN

To drop an existing column from a table, use the following syntax:

ALTER TABLE table_name DROP COLUMN column_name;

Examples

  1. Renaming a table:
ALTER TABLE employees RENAME TO staff;

This command will rename the employees table to staff.

  1. Renaming a column:
ALTER TABLE employees RENAME COLUMN first_name TO given_name;

This command will rename the first_name column to given_name in the employees table.

  1. Adding a new column:
ALTER TABLE employees ADD COLUMN department TEXT;

This command will add a new department column with the TEXT datatype to the employees table.

  1. Adding a new column with a default value:
ALTER TABLE employees ADD COLUMN active BOOLEAN DEFAULT true;

This command will add a new active column with the BOOLEAN datatype and a default value of true to the employees table.

  1. Dropping a column:
ALTER TABLE employees DROP COLUMN department;

This command will remove the department column from the employees table.

Summary

The ALTER TABLE statement is an essential SQL command that allows you to modify the structure of an existing table in a database. It supports renaming tables and columns, adding new columns with optional default values and constraints, and dropping existing columns. By understanding the ALTER TABLE syntax, you can efficiently manage your database schema and make necessary changes to your tables as your data requirements evolve.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/statements/data-definition/create-index/index.html b/docs/0.16.0/sql-syntax/statements/data-definition/create-index/index.html new file mode 100644 index 00000000..69a7da2c --- /dev/null +++ b/docs/0.16.0/sql-syntax/statements/data-definition/create-index/index.html @@ -0,0 +1,17 @@ + + + + + +CREATE INDEX | GlueSQL + + + + + +
+

CREATE INDEX

CREATE INDEX statement is used to create an index on one or more columns of a table. Indexes can improve query performance by allowing the database to quickly locate rows with specific column values. They can also be used with the ORDER BY clause to improve sorting performance. An index can be thought of as a data structure that maps the values of a specific column or columns to the corresponding rows in a table. This mapping allows the database to perform lookups and sorting operations more efficiently, as it does not have to scan the entire table.

Syntax

CREATE INDEX index_name ON table_name (column_name_expression);
  • index_name: The name of the index. It is recommended to use a descriptive name that indicates the purpose of the index, such as the column(s) it is based on.
  • table_name: The name of the table on which the index is to be created.
  • column_name_expression: The column name or expression on which the index is based. Only single column indexes are supported. If a column expression is used, it should be a simple arithmetic operation, such as addition or multiplication.

Example

Consider the following table called Students:

CREATE TABLE Students (
id INTEGER,
age INTEGER,
name TEXT
);

You can create an index on the id column with the following statement:

CREATE INDEX idx_id ON Students (id);

You can also create an index on a column expression, such as age * 2:

CREATE INDEX idx_age ON Students (age * 2);

Note that composite indexes (indexes on multiple columns) are not supported. These types of indexes can provide additional performance benefits in certain situations, but they also come with added complexity and increased storage requirements.

Using Index with ORDER BY

Indexes can improve the performance of the ORDER BY clause. When an index exists on the column specified in the ORDER BY clause, the database can use the index to sort the data more efficiently. This is because the index already provides a sorted view of the data, allowing the database to avoid the cost of sorting the entire table during query execution.

For example, if you have the following query:

SELECT * FROM Students ORDER BY id ASC;

The database can use the idx_id index created earlier to sort the data more quickly than without an index. Keep in mind that the performance gains from using an index with the ORDER BY clause will depend on the size of the table, the distribution of the data, and the specific database implementation.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/statements/data-definition/create-table/index.html b/docs/0.16.0/sql-syntax/statements/data-definition/create-table/index.html new file mode 100644 index 00000000..55a2eb68 --- /dev/null +++ b/docs/0.16.0/sql-syntax/statements/data-definition/create-table/index.html @@ -0,0 +1,17 @@ + + + + + +CREATE TABLE | GlueSQL + + + + + +
+

CREATE TABLE

The CREATE TABLE statement is a fundamental SQL command used to create a new table in a database. Tables are the primary structure in databases, as they hold the data organized in rows and columns. In this document, we'll explain the syntax and usage of the CREATE TABLE statement, including the IF NOT EXISTS clause.

Syntax

The basic syntax for the CREATE TABLE statement is as follows:

CREATE TABLE [IF NOT EXISTS] table_name (
column1 datatype constraint,
column2 datatype constraint,
column3 datatype constraint,
...
);
  • IF NOT EXISTS: This optional clause allows you to check if a table with the same name already exists in the database. If it exists, the command does nothing; otherwise, it creates a new table.
  • table_name: The name of the table you want to create.
  • column: Each column in the table is defined by its name, datatype, and optional constraints.
  • datatype: The type of data that the column will store (e.g., INTEGER, TEXT, DATE, etc.).
  • constraint: Optional constraints to enforce rules on the data stored in the column (e.g., PRIMARY KEY, NOT NULL, UNIQUE, etc.).

CREATE TABLE AS SELECT (CTAS)

You can also create a new table based on the result of a SELECT statement using the CTAS syntax:

CREATE TABLE table_name AS SELECT * FROM other_table;
  • table_name: The name of the new table to be created.
  • other_table: The existing table from which the data will be selected.

This command creates a new table with the same column structure as the source table and populates it with the data returned by the SELECT statement. The SELECT statement in this example uses the wildcard *, meaning that all columns from the source table will be included in the new table.

Example

Let's create a simple table called employees with the following columns:

  • id: A unique identifier for each employee (integer, primary key).
  • first_name: The employee's first name (text, not null).
  • last_name: The employee's last name (text, not null).
  • email: The employee's email address (text, unique).
  • hire_date: The date the employee was hired (date).

The SQL statement to create this table, using the IF NOT EXISTS clause, would look like this:

CREATE TABLE IF NOT EXISTS employees (
id INTEGER PRIMARY KEY,
first_name TEXT NOT NULL,
last_name TEXT NOT NULL,
email TEXT UNIQUE,
hire_date DATE
);

Example with CTAS

Assuming there is an existing table named employees_backup, you can create a new table called employees_copy with the same structure and data using CTAS:

CREATE TABLE employees_copy AS SELECT * FROM employees_backup;

Constraints

Constraints are rules that you can apply to columns in a table to control the data being stored. Some common constraints are:

  • PRIMARY KEY: Uniquely identifies each row in the table.
  • NOT NULL: Ensures the column cannot store a NULL value.
  • UNIQUE: Ensures all values in the column are unique.
  • DEFAULT: Sets a default value for the column when no value is specified.

Summary

The CREATE TABLE statement is an essential SQL command that allows you to create tables in a database. It requires a table name and one or more column definitions with their respective datatypes and optional constraints. The IF NOT EXISTS clause can be used to prevent creating duplicate tables. By understanding the CREATE TABLE syntax, you can define the structure of your tables and ensure the data stored in them is accurate and reliable.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/statements/data-definition/drop-index/index.html b/docs/0.16.0/sql-syntax/statements/data-definition/drop-index/index.html new file mode 100644 index 00000000..47495437 --- /dev/null +++ b/docs/0.16.0/sql-syntax/statements/data-definition/drop-index/index.html @@ -0,0 +1,17 @@ + + + + + +DROP INDEX | GlueSQL + + + + + +
+

DROP INDEX

DROP INDEX statement is used to remove an existing index from a table. This can be useful when an index is no longer needed, or if you want to free up storage space and reduce maintenance overhead associated with maintaining the index.

Syntax

DROP INDEX table_name.index_name;
  • table_name: The name of the table containing the index to be dropped.
  • index_name: The name of the index to be dropped.

Note that only one index can be dropped at a time using the DROP INDEX statement. If you want to drop multiple indexes, you need to execute multiple DROP INDEX statements.

Example

Consider the following table called Students with an index on the id column:

CREATE TABLE Students (
id INTEGER,
age INTEGER,
name TEXT
);

CREATE INDEX idx_id ON Students (id);

You can drop the idx_id index with the following statement:

DROP INDEX Students.idx_id;

If you attempt to drop multiple indexes in a single statement, an error will be raised:

DROP INDEX Students.idx_id, Students.idx_age;

This will result in an error, as only one index can be dropped at a time. To drop both indexes, execute two separate DROP INDEX statements:

DROP INDEX Students.idx_id;
DROP INDEX Students.idx_age;
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/statements/data-definition/drop-table/index.html b/docs/0.16.0/sql-syntax/statements/data-definition/drop-table/index.html new file mode 100644 index 00000000..fb0fd89e --- /dev/null +++ b/docs/0.16.0/sql-syntax/statements/data-definition/drop-table/index.html @@ -0,0 +1,17 @@ + + + + + +DROP TABLE | GlueSQL + + + + + +
+

DROP TABLE

The DROP TABLE statement is an SQL command used to remove one or more tables from a database. This operation is useful when you no longer need a table or want to clear out old data structures. In this document, we'll explain the syntax and usage of the DROP TABLE statement, including the IF EXISTS clause and dropping multiple tables at once.

Syntax

The basic syntax for the DROP TABLE statement is as follows:

DROP TABLE [IF EXISTS] table_name [, table_name2, ...];
  • IF EXISTS: This optional clause allows you to check if a table exists in the database before attempting to drop it. If the table does not exist, the command does nothing; otherwise, it drops the specified table.
  • table_name: The name of the table you want to drop. You can also drop multiple tables by separating their names with commas.

Examples

  1. Dropping a single table:
DROP TABLE employees;

This command will drop the employees table from the database.

  1. Dropping a table using the IF EXISTS clause:
DROP TABLE IF EXISTS employees;

This command will drop the employees table if it exists in the database. If the table does not exist, the command does nothing.

  1. Dropping multiple tables at once:
DROP TABLE employees, table_name;

This command will drop both the employees and table_name tables from the database.

Warning

When using the DROP TABLE statement, be cautious, as this operation will permanently remove the table and all its data from the database. Always make sure to backup your data before performing this operation.

Summary

The DROP TABLE statement is an essential SQL command that allows you to remove tables from a database. It supports an optional IF EXISTS clause to prevent errors if a table does not exist, and you can drop multiple tables at once by separating their names with commas. By understanding the DROP TABLE syntax, you can efficiently manage your database schema and remove unnecessary tables when needed.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/statements/data-manipulation/delete/index.html b/docs/0.16.0/sql-syntax/statements/data-manipulation/delete/index.html new file mode 100644 index 00000000..03891ee2 --- /dev/null +++ b/docs/0.16.0/sql-syntax/statements/data-manipulation/delete/index.html @@ -0,0 +1,17 @@ + + + + + +DELETE | GlueSQL + + + + + +
+

DELETE

The DELETE statement is used to remove records from a table. You can delete a single row, multiple rows, or all rows at once based on specific conditions.

Basic DELETE Syntax

To delete records from a table, use the following syntax:

DELETE FROM table_name
WHERE condition;

If you want to delete all records from a table, you can omit the WHERE clause:

DELETE FROM table_name;

Examples

Consider the following Foo table:

CREATE TABLE Foo (
id INTEGER PRIMARY KEY,
score INTEGER,
flag BOOLEAN
);

With the following records:

INSERT INTO Foo VALUES
(1, 100, TRUE),
(2, 300, FALSE),
(3, 700, TRUE);

Deleting Records with a WHERE Clause

To delete records that meet a specific condition, use the WHERE clause:

DELETE FROM Foo WHERE flag = FALSE;

After executing the above query, the remaining records in the Foo table will be:

id | score | flag
---+-------+------
1 | 100 | true
3 | 700 | true

Deleting All Records

To delete all records from a table, omit the WHERE clause:

DELETE FROM Foo;

After executing the above query, the Foo table will be empty:

id | score | flag
(no rows)
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/statements/data-manipulation/insert/index.html b/docs/0.16.0/sql-syntax/statements/data-manipulation/insert/index.html new file mode 100644 index 00000000..406d4e81 --- /dev/null +++ b/docs/0.16.0/sql-syntax/statements/data-manipulation/insert/index.html @@ -0,0 +1,17 @@ + + + + + +INSERT | GlueSQL + + + + + +
+

INSERT

The INSERT statement is used to insert new records into a table. You can insert a single row or multiple rows at once, and you can also use the NULL, NOT NULL, and DEFAULT constraints to define how values are inserted.

Basic INSERT Syntax

INSERT INTO table_name (column1, column2, column3, ...)
VALUES
(value1, value2, value3, ...),
(value4, value5, value6, ...),
...
;

Handling NULL, NOT NULL, and DEFAULT Constraints

When inserting data into a table, the database handles NULL, NOT NULL, and DEFAULT constraints as follows:

  • NULL: If a column is defined with the NULL constraint (or no constraint is provided), you can insert a NULL value or omit the column in the INSERT statement. The database will store a NULL value for the omitted column.

  • NOT NULL: If a column is defined with the NOT NULL constraint, you must provide a value for the column in the INSERT statement. If you try to insert a NULL value or omit the column, the database will return an error.

  • DEFAULT: If a column is defined with a DEFAULT value, you can omit the column in the INSERT statement. The database will automatically use the default value for the omitted column.

Examples

Consider the following Test table:

CREATE TABLE Test (
id INTEGER DEFAULT 1,
num INTEGER NULL,
name TEXT NOT NULL,
);

Basic INSERT

To insert a single row:

INSERT INTO Test (id, num, name) VALUES (1, 2, 'Hi boo');

Inserting Multiple Rows

To insert multiple rows at once:

INSERT INTO Test (id, num, name)
VALUES
(3, 9, 'Kitty!'),
(2, 7, 'Monsters');

Inserting with Omitted Columns

If you want to insert a row without specifying a value for a column with a DEFAULT constraint, you can simply omit the column:

INSERT INTO Test (num, name) VALUES (28, 'Wazowski');

For columns with NULL constraint, you can either omit the column or explicitly insert a NULL value:

INSERT INTO Test (name) VALUES ('The end');

Handling NOT NULL Constraint

If you try to insert a row without specifying a value for a column with the NOT NULL constraint, the database will return an error:

INSERT INTO Test (id, num) VALUES (1, 10);
-- Error: LackOfRequiredColumn("name")
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/statements/data-manipulation/update/index.html b/docs/0.16.0/sql-syntax/statements/data-manipulation/update/index.html new file mode 100644 index 00000000..625a2c3f --- /dev/null +++ b/docs/0.16.0/sql-syntax/statements/data-manipulation/update/index.html @@ -0,0 +1,17 @@ + + + + + +UPDATE | GlueSQL + + + + + +
+

UPDATE

The UPDATE statement is used to modify existing records in a table. You can update one or more columns with new values, or even use subqueries to update values based on other tables.

Basic UPDATE Syntax

UPDATE table_name
SET column1 = value1, column2 = value2, ...
WHERE condition;

Examples

Updating a Single Column

Consider the following TableA:

idnumnum2name
124Hello
195World
347Great
4710Job

To update the id column for all rows in TableA, you can use the following query:

UPDATE TableA SET id = 2;

The resulting TableA would look like this:

idnumnum2name
224Hello
295World
247Great
2710Job

Updating with a Condition

If you want to update only specific rows that meet a certain condition, you can use the WHERE clause. For example, to update the id column only for the row with num = 9:

UPDATE TableA SET id = 4 WHERE num = 9;

Updating with a Subquery

You can also use a subquery in the UPDATE statement to update a column based on other table's values. For example, to update the num2 column in TableA with the rank column value from TableB where the num column values match, and the num = 7:

UPDATE TableA SET num2 = (SELECT rank FROM TableB WHERE num = TableA.num) WHERE num = 7;

Updating Based on the Result of Another Query

You can update a column based on the result of another query. For example, to update the num2 column in TableA with the rank column value from TableB where the num column values match, and the num is the minimum num in TableA:

UPDATE TableA SET num2 = (SELECT rank FROM TableB WHERE num = TableA.num) WHERE num = (SELECT MIN(num) FROM TableA);

Not Supported Features

  • Using JOIN in an UPDATE statement is not supported.
  • Updating a table using compound identifiers (e.g., ErrTestTable.id = 1) is not supported.
  • Updating a non-existent table will result in a TableNotFound error.
  • Updating a non-existent column will result in a ColumnNotFound error.
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/statements/metadata/data-dictionary/index.html b/docs/0.16.0/sql-syntax/statements/metadata/data-dictionary/index.html new file mode 100644 index 00000000..c56088c9 --- /dev/null +++ b/docs/0.16.0/sql-syntax/statements/metadata/data-dictionary/index.html @@ -0,0 +1,17 @@ + + + + + +Data Dictionary | GlueSQL + + + + + +
+

Data Dictionary

In GlueSQL, there are predefined tables, also known as Data Dictionary tables, which store metadata about the database objects like tables, columns, and indexes. These tables can be queried like any other table in the database, and they provide useful information about the database schema.

The Data Dictionary tables in GlueSQL include:

  1. GLUE_TABLES
  2. GLUE_TABLE_COLUMNS
  3. GLUE_INDEXES

Please note that the columns provided in these tables are the default columns. Storage implementations may provide additional information in these tables.

GLUE_TABLES

The GLUE_TABLES table contains a list of all tables in the database.

Columns:

  • TABLE_NAME: The name of the table.

GLUE_TABLE_COLUMNS

The GLUE_TABLE_COLUMNS table contains information about the columns in each table.

Columns:

  • TABLE_NAME: The name of the table that the column belongs to.
  • COLUMN_NAME: The name of the column.
  • COLUMN_ID: The column's unique identifier.

GLUE_INDEXES

The GLUE_INDEXES table contains information about the indexes defined in the database.

Columns:

  • TABLE_NAME: The name of the table that the index belongs to.
  • INDEX_NAME: The name of the index.
  • ORDER: The order in which the index is sorted (e.g., "ASC", "DESC", or "BOTH").
  • EXPRESSION: The expression used for the indexed column (e.g., "id" or "id + 2").
  • UNIQUENESS: A boolean value indicating whether the index enforces uniqueness.

Examples

To query the GLUE_TABLES table and get a list of all tables in the database:

SELECT * FROM GLUE_TABLES;

To query the GLUE_TABLE_COLUMNS table and get information about the columns in each table:

SELECT * FROM GLUE_TABLE_COLUMNS;

To query the GLUE_INDEXES table and get information about the indexes defined in the database:

SELECT * FROM GLUE_INDEXES;
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/statements/metadata/show-tables/index.html b/docs/0.16.0/sql-syntax/statements/metadata/show-tables/index.html new file mode 100644 index 00000000..5a313446 --- /dev/null +++ b/docs/0.16.0/sql-syntax/statements/metadata/show-tables/index.html @@ -0,0 +1,17 @@ + + + + + +SHOW TABLES | GlueSQL + + + + + +
+

SHOW TABLES

The SHOW TABLES statement in GlueSQL is used to display a list of tables available in the database. This statement is useful when you want to inspect the current structure of your database or when you want to manage multiple tables.

Syntax

SHOW TABLES;

Example

Consider the following example where we create a few tables and then use the SHOW TABLES statement to list them:

CREATE TABLE Foo (id INTEGER, name TEXT NULL, type TEXT NULL);
CREATE TABLE Zoo (id INTEGER);
CREATE TABLE Bar (id INTEGER, name TEXT NULL);

SHOW TABLES;

The output of the SHOW TABLES statement will be:

Bar
Foo
Zoo

The tables are listed in alphabetical order.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/statements/querying/aggregation/index.html b/docs/0.16.0/sql-syntax/statements/querying/aggregation/index.html new file mode 100644 index 00000000..ee538c9d --- /dev/null +++ b/docs/0.16.0/sql-syntax/statements/querying/aggregation/index.html @@ -0,0 +1,17 @@ + + + + + +Aggregation | GlueSQL + + + + + +
+

Aggregation

GlueSQL supports several aggregate functions to perform calculations on a set of values. Below is a list of supported aggregate functions along with a brief explanation of each:

  • COUNT: Counts the number of non-NULL values in the specified column.
  • AVG: Calculates the average of non-NULL values in the specified column.
  • SUM: Calculates the sum of non-NULL values in the specified column.
  • MAX: Returns the maximum value in the specified column.
  • MIN: Returns the minimum value in the specified column.
  • STDEV: Calculates the population standard deviation of non-NULL values in the specified column.
  • VARIANCE: Calculates the population variance of non-NULL values in the specified column.

In addition to the aggregate functions, you can use GROUP BY and HAVING clauses to group and filter the results based on specific conditions.

GROUP BY

The GROUP BY clause is used to group rows with the same values in specified columns into a set of summary rows. It is often used with aggregate functions to perform calculations on each group of rows.

Here's an example that groups the items by city and calculates the sum of quantity and the count of items for each city:

SELECT SUM(quantity), COUNT(*), city FROM Item GROUP BY city;

HAVING

The HAVING clause is used to filter the results of a GROUP BY query based on a condition that applies to the summary rows. It is similar to the WHERE clause but operates on the results of the grouping.

Here's an example that groups the items by city and calculates the sum of quantity and the count of items for each city, but only includes cities with a count greater than 1:

SELECT SUM(quantity), COUNT(*), city FROM Item GROUP BY city HAVING COUNT(*) > 1;

In the examples provided, you can see the usage of GROUP BY and HAVING clauses in combination with aggregate functions to retrieve data from the Item table.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/statements/querying/join/index.html b/docs/0.16.0/sql-syntax/statements/querying/join/index.html new file mode 100644 index 00000000..4c035965 --- /dev/null +++ b/docs/0.16.0/sql-syntax/statements/querying/join/index.html @@ -0,0 +1,17 @@ + + + + + +JOIN | GlueSQL + + + + + +
+

JOIN

GlueSQL supports two types of JOIN operations:

  • (INNER) JOIN
  • LEFT (OUTER) JOIN

Please note that FULL OUTER JOIN and RIGHT JOIN are currently not supported.

(INNER) JOIN

An INNER JOIN combines rows from two tables based on a specified condition. Rows that do not satisfy the condition are excluded from the result.

Here's an example using the provided test code:

SELECT * FROM Item INNER JOIN Player ON Player.id = Item.player_id WHERE Player.id = 1;

This query retrieves all rows from the Item and Player tables where the id in the Player table matches the player_id in the Item table, and the Player.id is equal to 1.

LEFT (OUTER) JOIN

A LEFT JOIN (also known as LEFT OUTER JOIN) combines rows from two tables based on a specified condition. For each row in the left table that does not have a matching row in the right table, the result will contain NULL values.

Here's an example using the provided test code:

SELECT * FROM Item LEFT JOIN Player ON Player.id = Item.player_id WHERE quantity = 1;

This query retrieves all rows from the Item table and any matching rows from the Player table where the id in the Player table matches the player_id in the Item table. If there's no match, NULL values are returned for the Player table columns. The result is then filtered by the quantity column in the Item table with a value of 1.

Remember to replace the table names, column names, and data types as needed for your specific use case.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/statements/querying/limit/index.html b/docs/0.16.0/sql-syntax/statements/querying/limit/index.html new file mode 100644 index 00000000..b36ede69 --- /dev/null +++ b/docs/0.16.0/sql-syntax/statements/querying/limit/index.html @@ -0,0 +1,17 @@ + + + + + +LIMIT & OFFSET | GlueSQL + + + + + +
+

LIMIT & OFFSET

LIMIT and OFFSET are SQL clauses that allow you to control the number of rows returned by a SELECT statement. They are particularly useful when you need to paginate or retrieve a specific portion of the result set.

LIMIT

The LIMIT clause restricts the number of rows returned by a query. The syntax for using LIMIT is:

SELECT columns FROM table_name
LIMIT number_of_rows;

OFFSET

The OFFSET clause is used in combination with LIMIT to skip a specific number of rows before starting to return the rows. The syntax for using OFFSET is:

SELECT columns FROM table_name
LIMIT number_of_rows
OFFSET number_of_rows_to_skip;

You can also use OFFSET without LIMIT:

SELECT columns FROM table_name
OFFSET number_of_rows_to_skip;

Examples

Consider the following Test table:

CREATE TABLE Test (
id INTEGER
);

With the following records:

INSERT INTO Test VALUES (1), (2), (3), (4), (5), (6), (7), (8);

Using LIMIT

Retrieve the first 3 rows from the Test table:

SELECT * FROM Test LIMIT 3;

Result:

id
---
1
2
3

Using LIMIT and OFFSET

Retrieve the next 4 rows after the first 3 rows from the Test table:

SELECT * FROM Test LIMIT 4 OFFSET 3;

Result:

id
---
4
5
6
7

Using OFFSET without LIMIT

Retrieve all rows after the first 2 rows from the Test table:

SELECT * FROM Test OFFSET 2;

Result:

id
---
3
4
5
6
7
8
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/statements/querying/schemaless/index.html b/docs/0.16.0/sql-syntax/statements/querying/schemaless/index.html new file mode 100644 index 00000000..a8917d86 --- /dev/null +++ b/docs/0.16.0/sql-syntax/statements/querying/schemaless/index.html @@ -0,0 +1,17 @@ + + + + + +Schemaless Data | GlueSQL + + + + + +
+

Querying Schemaless Data

GlueSQL is an SQL database that provides a unique feature: it allows you to work with schemaless data, similar to NoSQL databases. Please note this point in the documentation.

Creating a Schemaless Table

To create a schemaless table, you don't need to specify columns when creating the table. For example:

CREATE TABLE Sample;

This creates a schemaless table. You can now insert data freely into each row, like a NoSQL database. Nested data is also supported.

Example SQL Queries

Here are some example SQL queries that demonstrate how to use GlueSQL with schemaless data:

Creating Tables

CREATE TABLE Player;
CREATE TABLE Item;

Inserting Data

INSERT INTO Player VALUES ('{"id": 1001, "name": "Beam", "flag": 1}'), ('{"id": 1002, "name": "Seo"}');
INSERT INTO Item VALUES ('{"id": 100, "name": "Test 001", "dex": 324, "rare": false, "obj": {"cost": 3000}}'), ('{"id": 200}');

Selecting Data

SELECT name, dex, rare FROM Item WHERE id = 100;
SELECT name, dex, rare FROM Item;
SELECT * FROM Item;

Updating Data

DELETE FROM Item WHERE id > 100;
UPDATE Item SET id = id + 1, rare = NOT rare;
UPDATE Item SET new_field = 'Hello';

Selecting with Aliases and Joins

SELECT
Player.id AS player_id,
Player.name AS player_name,
Item.obj['cost'] AS item_cost
FROM Item
JOIN Player
WHERE flag IS NOT NULL;

Notable Exception Cases

Here are some example SQL queries that will raise errors, along with explanations of the issues:

Inserting Invalid Data

  • Inserting multiple values for a schemaless row:

    INSERT INTO Item VALUES ('{"a": 10}', '{"b": true}');

    Schemaless rows accept only single values.

  • Inserting data from a SELECT statement:

    INSERT INTO Item SELECT id, name FROM Item LIMIT 1;

    Schemaless rows cannot be inserted using a SELECT statement.

  • Inserting a JSON array:

    INSERT INTO Item VALUES ('[1, 2, 3]');

    Only JSON objects are allowed for schemaless rows.

  • Inserting a boolean value:

    INSERT INTO Item VALUES (true);

    Text literals are required for schemaless rows.

  • Inserting an expression result:

    INSERT INTO Item VALUES (CAST(1 AS INTEGER) + 4);

    Map or string values are required for schemaless rows.

  • Inserting data from a SELECT statement with LIMIT:

    INSERT INTO Item SELECT id FROM Item LIMIT 1;

    Map type values are required for schemaless rows.

Selecting Invalid Data

  • Using IN with a schemaless subquery:

    SELECT id FROM Item WHERE id IN (SELECT * FROM Item);

    Schemaless projections are not allowed for IN subqueries.

  • Using a comparison with a schemaless subquery:

    SELECT id FROM Item WHERE id = (SELECT * FROM Item LIMIT 1);

    Schemaless projections are not allowed for subqueries.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/statements/querying/where/index.html b/docs/0.16.0/sql-syntax/statements/querying/where/index.html new file mode 100644 index 00000000..7773dcef --- /dev/null +++ b/docs/0.16.0/sql-syntax/statements/querying/where/index.html @@ -0,0 +1,17 @@ + + + + + +WHERE | GlueSQL + + + + + +
+

WHERE

In GlueSQL, the WHERE clause is used to filter the results of a SELECT query based on specific conditions. The WHERE clause can be used with various operators and functions to create complex filtering conditions.

Here are some examples based on the provided Rust test code and SQL queries:

Comparison Operators

You can use comparison operators such as =, <>, <, >, <=, and >= to compare values in the WHERE clause.

SELECT name FROM Boss WHERE id <= 2;
SELECT name FROM Boss WHERE +id <= 2;

BETWEEN Operator

The BETWEEN operator allows you to filter results within a specific range.

SELECT id, name FROM Boss WHERE id BETWEEN 2 AND 4;
SELECT id, name FROM Boss WHERE name BETWEEN 'Doll' AND 'Gehrman';

To exclude the specified range, use the NOT BETWEEN operator.

SELECT name FROM Boss WHERE name NOT BETWEEN 'Doll' AND 'Gehrman';

EXISTS and NOT EXISTS

EXISTS and NOT EXISTS operators are used to filter results based on the existence of records in a subquery.

SELECT name
FROM Boss
WHERE EXISTS (
SELECT * FROM Hunter WHERE Hunter.name = Boss.name
);

SELECT name
FROM Boss
WHERE NOT EXISTS (
SELECT * FROM Hunter WHERE Hunter.name = Boss.name
);

IN Operator

The IN operator allows you to filter results based on a list of values or a subquery.

SELECT * FROM Player WHERE id IN (SELECT user_id FROM Request WHERE quantity IN (6, 7, 8, 9));

LIKE and ILIKE Operators

LIKE and ILIKE operators are used to filter results based on pattern matching. Use the % wildcard to match any number of characters and the _ wildcard to match a single character.

SELECT name FROM Item WHERE name LIKE '_a%';
SELECT name FROM Item WHERE name LIKE '%r%';

ILIKE is a case-insensitive version of LIKE.

SELECT name FROM Item WHERE name ILIKE '%%';
SELECT name FROM Item WHERE name NOT ILIKE '%A%';
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/sql-syntax/statements/transaction/index.html b/docs/0.16.0/sql-syntax/statements/transaction/index.html new file mode 100644 index 00000000..7441d2c1 --- /dev/null +++ b/docs/0.16.0/sql-syntax/statements/transaction/index.html @@ -0,0 +1,17 @@ + + + + + +Transaction | GlueSQL + + + + + +
+

Transaction

Transactions in SQL are a series of queries that are executed as a single unit of work. In GlueSQL, transactions help to ensure the consistency and integrity of the database. They follow the ACID properties: Atomicity, Consistency, Isolation, and Durability.

Note: In GlueSQL, transactions are an optional feature. Support for transactions depends on the storage engine being used. Currently, only SledStorage supports transactions, but there are plans to add support for other storage engines in the future. Transaction isolation levels may also vary depending on the storage engine. For example, the current transaction isolation level for SledStorage is SNAPSHOT ISOLATION.

BEGIN TRANSACTION

To start a new transaction, use the BEGIN keyword:

BEGIN;

COMMIT TRANSACTION

To permanently save the changes made during the transaction, use the COMMIT keyword:

COMMIT;

ROLLBACK TRANSACTION

To undo the changes made during the transaction and revert the database to its state before the transaction started, use the ROLLBACK keyword:

ROLLBACK;

Example

Consider the following table TxTest with columns id (INTEGER) and name (TEXT):

CREATE TABLE TxTest (
id INTEGER,
name TEXT
);

Insert sample data into the table:

INSERT INTO TxTest VALUES
(1, 'Friday'),
(2, 'Phone');

Inserting Data

Start a new transaction and insert a new row:

BEGIN;
INSERT INTO TxTest VALUES (3, 'New one');

Rollback the transaction to undo the insertion:

ROLLBACK;

Now, start a new transaction and insert a new row with different data:

BEGIN;
INSERT INTO TxTest VALUES (3, 'Vienna');
COMMIT;

Deleting Data

Start a new transaction and delete a row:

BEGIN;
DELETE FROM TxTest WHERE id = 3;
ROLLBACK;

The deletion will be undone due to the rollback. To permanently delete the row, commit the transaction:

BEGIN;
DELETE FROM TxTest WHERE id = 3;
COMMIT;

Updating Data

Start a new transaction and update a row:

BEGIN;
UPDATE TxTest SET name = 'Sunday' WHERE id = 1;
ROLLBACK;

The update will be undone due to the rollback. To permanently update the row, commit the transaction:

BEGIN;
UPDATE TxTest SET name = 'Sunday' WHERE id = 1;
COMMIT;
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/storages/developing-custom-storages/intro/index.html b/docs/0.16.0/storages/developing-custom-storages/intro/index.html new file mode 100644 index 00000000..05f036c7 --- /dev/null +++ b/docs/0.16.0/storages/developing-custom-storages/intro/index.html @@ -0,0 +1,17 @@ + + + + + +Introduction | GlueSQL + + + + + +
+

Introduction

With GlueSQL, you can adapt SQL and the AST Builder to a wide variety of environments. This includes file systems, key-value databases, complex NoSQL databases, and even remote APIs. As long as a system supports reading, it can support SELECT queries. If it supports both reading and writing, it can support most SQL operations, including UPDATE and DELETE.

To implement GlueSQL, you only need to know two things:

  1. Understanding Store traits
  2. Using the Test Suite

These topics are covered in more detail in their respective pages, but here we will provide a brief overview.

Understanding Store Traits

GlueSQL is available in both Rust and JavaScript environments, with plans to expand its support to other languages. Since the GlueSQL project itself is written in Rust, using Rust is essential for developing custom storages. To create a custom storage, you need to implement the Store traits provided by GlueSQL. There are currently 9 traits:

  • Store - A trait for read operations to support SELECT queries.
  • StoreMut - A trait for modifying data, such as INSERT, UPDATE, and DELETE.
  • AlterTable - A trait for supporting schema changes.
  • Transaction - A trait for supporting transactions.
  • CustomFunction - A trait for supporting user-level custom functions.
  • CustomFunctionMut - A trait for creating or deleting user-level custom functions.
  • Index - A trait for supporting non-clustered indexes. This trait allows you to process pre-registered indexes.
  • IndexMut - A trait for creating or deleting non-clustered indexes.
  • Metadata - A trait for querying metadata.

To develop a custom storage, you can implement these 9 traits. Although this may seem like a lot of work, don't worry. All traits except for Store and StoreMut are optional. In other words, you don't have to implement them. If you don't want to support the AlterTable trait, simply don't implement it. It's that simple.

Furthermore, if you only want to support SELECT queries, you don't need to implement StoreMut. By implementing only the Store trait, you can create a custom storage that supports SQL SELECT queries.

Using the Test Suite

The minimum requirement for developing a custom storage is implementing the Store traits. However, you may want to verify that your implementation is correct. That's where the Test Suite comes in.

GlueSQL provides a test case library to make it easy to validate custom storage development. Developers can implement the desired Store traits and use the Test Suite to verify that their implementation is correct. The line coverage of GlueSQL's core project is almost 99%, which means that passing the Test Suite alone can complete most of the feature verification. All you need to do is ensure your custom storage passes the Test Suite and write additional tests for any specialized features specific to your storage.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/storages/developing-custom-storages/store-traits/alter-table/index.html b/docs/0.16.0/storages/developing-custom-storages/store-traits/alter-table/index.html new file mode 100644 index 00000000..716f6cc9 --- /dev/null +++ b/docs/0.16.0/storages/developing-custom-storages/store-traits/alter-table/index.html @@ -0,0 +1,17 @@ + + + + + +AlterTable | GlueSQL + + + + + +
+

AlterTable

The AlterTable trait corresponds to the SQL ALTER TABLE statement and is used for modifying existing schemas. It is not necessary to implement the AlterTable trait. If you are dealing with data that is difficult to modify schema-wise or schemaless data, there is no need to implement the AlterTable trait. It is an optional trait that custom storage developers can choose to implement.

Similar to the Store & StoreMut combination, if you implement the AlterTable trait, you can use additional tests in the Test Suite to verify your implementation. There are currently four types of methods supported by AlterTable:

  1. rename_schema: Corresponds to the SQL statement ALTER TABLE {table-name} RENAME TO {other-name};. This method renames a schema.

  2. rename_column: Corresponds to the SQL statement ALTER TABLE {table-name} RENAME COLUMN {col1} TO {col2};. This method renames a column within a table.

  3. add_column: Corresponds to the SQL statement ALTER TABLE {table-name} ADD COLUMN {col} {data-type} {constraints}. This method adds a new column to a table with specified data type and constraints.

  4. drop_column: Corresponds to the SQL statement ALTER TABLE {table-name} DROP COLUMN {col}. This method removes a column from a table.

#[async_trait(?Send)]
pub trait AlterTable {
async fn rename_schema(&mut self, _table_name: &str, _new_table_name: &str) -> Result<()>;

async fn rename_column(&mut self,
_table_name: &str,
_old_column_name: &str,
_new_column_name: &str,
) -> Result<()>;

async fn add_column(&mut self, _table_name: &str, _column_def: &ColumnDef) -> Result<()>;

async fn drop_column(
&mut self,
_table_name: &str,
_column_name: &str,
_if_exists: bool,
) -> Result<()>;
}
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/storages/developing-custom-storages/store-traits/custom-function-mut/index.html b/docs/0.16.0/storages/developing-custom-storages/store-traits/custom-function-mut/index.html new file mode 100644 index 00000000..15a97129 --- /dev/null +++ b/docs/0.16.0/storages/developing-custom-storages/store-traits/custom-function-mut/index.html @@ -0,0 +1,17 @@ + + + + + +CustomFunctionMut | GlueSQL + + + + + +
+

CustomFunctionMut

By implementing both the CustomFunction and CustomFunctionMut traits, users can create, use, and delete user-level custom functions. Although GlueSQL plans to continuously add various functions, users may still find them insufficient. In such cases, users can create their own user-level custom functions to supplement the built-in functions. Additionally, if there are repetitive business logic codes, they can be stored as custom functions.

Example:

CREATE FUNCTION ADD_ONE (n INT, x INT DEFAULT 1) RETURN n + x;

SELECT ADD_ONE(10) AS test;

DROP FUNCTION ADD_ONE;

There are two methods available:

  1. insert_function: This method inserts a new custom function into the storage system.

  2. delete_function: This method deletes a custom function from the storage system using the provided function name.

#[async_trait(?Send)]
pub trait CustomFunctionMut {
async fn insert_function(&mut self, _func: StructCustomFunction) -> Result<()>;

async fn delete_function(&mut self, _func_name: &str) -> Result<()>;
}
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/storages/developing-custom-storages/store-traits/custom-function/index.html b/docs/0.16.0/storages/developing-custom-storages/store-traits/custom-function/index.html new file mode 100644 index 00000000..ea628606 --- /dev/null +++ b/docs/0.16.0/storages/developing-custom-storages/store-traits/custom-function/index.html @@ -0,0 +1,17 @@ + + + + + +CustomFunction | GlueSQL + + + + + +
+

CustomFunction

The CustomFunction trait is an optional trait for supporting user-level custom functions. Through the CustomFunction trait, you can retrieve custom functions stored in the storage system. You can choose to implement the CustomFunction trait alone or together with the CustomFunctionMut trait.

In some cases, you might want to provide storage-specific functions pre-built and separately available for each storage system. In such cases, you can implement the CustomFunction trait and create additional functions stored in advance when using it. To achieve this, the CustomFunction and CustomFunctionMut traits are provided separately for implementation.

There are two methods available:

  1. fetch_function: This method retrieves a custom function from the storage system using the provided function name.

  2. fetch_all_functions: This method retrieves all custom functions stored in the storage system.

#[async_trait(?Send)]
pub trait CustomFunction {
async fn fetch_function(&self, _func_name: &str) -> Result<Option<&StructCustomFunction>>;

async fn fetch_all_functions(&self) -> Result<Vec<&StructCustomFunction>>;
}
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/storages/developing-custom-storages/store-traits/index-mut/index.html b/docs/0.16.0/storages/developing-custom-storages/store-traits/index-mut/index.html new file mode 100644 index 00000000..72488fc5 --- /dev/null +++ b/docs/0.16.0/storages/developing-custom-storages/store-traits/index-mut/index.html @@ -0,0 +1,17 @@ + + + + + +IndexMut | GlueSQL + + + + + +
+

IndexMut

The IndexMut trait, when implemented along with the Index trait, allows custom storage developers to provide users with the ability to create, use, and delete non-clustered indexes. Implementing the IndexMut trait enhances the storage system's capabilities by providing support for dynamic index management.

Non-clustered indexes can improve query performance by reducing the amount of data that needs to be read during search operations. Users can create multiple non-clustered indexes tailored to their specific use cases, providing a more efficient and optimized experience when working with large datasets.

The IndexMut trait requires the implementation of two methods:

  1. create_index: This method creates a new non-clustered index on the specified column with a given index name for the provided table. The index can be used to speed up queries involving the indexed column.

  2. drop_index: This method removes a non-clustered index by the specified index name from the provided table. This can be useful when the index is no longer needed or needs to be updated to reflect changes in the data.

#[async_trait(?Send)]
pub trait IndexMut {
async fn create_index(
&mut self,
_table_name: &str,
_index_name: &str,
_column: &OrderByExpr,
) -> Result<()>;

async fn drop_index(&mut self, _table_name: &str, _index_name: &str) -> Result<()>;
}

By implementing both the Index and IndexMut traits, custom storage developers can provide users with the ability to manage non-clustered indexes according to their specific needs, improving overall query performance and providing a more tailored experience.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/storages/developing-custom-storages/store-traits/index-trait/index.html b/docs/0.16.0/storages/developing-custom-storages/store-traits/index-trait/index.html new file mode 100644 index 00000000..3d6e615a --- /dev/null +++ b/docs/0.16.0/storages/developing-custom-storages/store-traits/index-trait/index.html @@ -0,0 +1,17 @@ + + + + + +Index | GlueSQL + + + + + +
+

Index

The Index trait is designed to support non-clustered indexes. If you only need to support pre-built non-clustered indexes, implementing the Index trait without the IndexMut trait is sufficient. Note that clustered indexes (PRIMARY KEY) are automatically supported by the Store & StoreMut implementations. The Index trait is specifically for non-clustered index support.

Currently, GlueSQL's query planner only supports a logical planner, so the performance of finding non-clustered indexes is not optimal yet, but it is being improved. If you want to use non-clustered indexes more precisely, using the AST Builder to directly specify the index you want to use can be a good approach.

A brief explanation of non-clustered and clustered indexes:

  • Non-clustered index: A non-clustered index is an index that doesn't affect the physical ordering of the data rows in the table. Instead, it maintains a separate data structure that contains a reference to the actual data rows, allowing for faster search operations without rearranging the data itself.

  • Clustered index: A clustered index determines the physical order of the data in the table. In other words, the data rows are stored on disk in the same order as the index. There can be only one clustered index per table, which is usually defined by the PRIMARY KEY constraint.

There is one method to implement for the Index trait:

  1. scan_indexed_data: This method retrieves indexed data from the storage system using the provided table name, index name, sorting order, and comparison value.
#[async_trait(?Send)]
pub trait Index {
async fn scan_indexed_data(
&self,
_table_name: &str,
_index_name: &str,
_asc: Option<bool>,
_cmp_value: Option<(&IndexOperator, Value)>,
) -> Result<RowIter>;
}
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/storages/developing-custom-storages/store-traits/metadata/index.html b/docs/0.16.0/storages/developing-custom-storages/store-traits/metadata/index.html new file mode 100644 index 00000000..e783d9ea --- /dev/null +++ b/docs/0.16.0/storages/developing-custom-storages/store-traits/metadata/index.html @@ -0,0 +1,17 @@ + + + + + +Metadata | GlueSQL + + + + + +
+

Metadata

The Metadata trait is an optional implementation for providing additional metadata support in GlueSQL. GlueSQL does not enforce any specific metadata implementation, allowing custom storage developers to decide which type of metadata, such as create time, modify time, etc., they want to provide.

Implementing the Metadata trait can be beneficial in cases where users need to access and manage metadata related to tables, columns, or other database objects. This can help users understand the structure and properties of their data, ensuring proper management and organization.

Currently, the Metadata trait supports the scan_table_meta method for retrieving table metadata. The metadata provided by the storage can be queried using the data dictionary table GLUE_TABLES.

type ObjectName = String;
pub type MetaIter = Box<dyn Iterator<Item = Result<(ObjectName, HashMap<String, Value>)>>>;

#[async_trait(?Send)]
pub trait Metadata {
async fn scan_table_meta(&self) -> Result<MetaIter> {
Ok(Box::new(empty()))
}
}

By implementing the Metadata trait, custom storage developers can provide users with a way to access and manage metadata related to various database objects. This can be particularly useful in situations where users need to understand the properties of their data or maintain a well-organized database structure.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/storages/developing-custom-storages/store-traits/store-mut/index.html b/docs/0.16.0/storages/developing-custom-storages/store-traits/store-mut/index.html new file mode 100644 index 00000000..10eda9b6 --- /dev/null +++ b/docs/0.16.0/storages/developing-custom-storages/store-traits/store-mut/index.html @@ -0,0 +1,17 @@ + + + + + +StoreMut | GlueSQL + + + + + +
+

StoreMut

While the Store trait is for supporting SELECT queries and reading data, the StoreMut trait is for modifying data. Implementing the StoreMut trait requires the implementation of the Store trait as well. By implementing both the Store and StoreMut traits, you can support most of the commonly used SQL statements. Additionally, you can use the Test Suite to utilize the integration test set provided by GlueSQL. Custom storage developers can verify their own Store & StoreMut implementations by checking if they pass all the tests provided in the Test Suite.

Here are the five methods required to implement the StoreMut trait:

  1. insert_schema: This method is responsible for inserting a new schema into the storage system.

  2. delete_schema: This method is for deleting a schema from the storage system using the provided table name.

  3. append_data: This method appends a list of data rows to an existing table in the storage system.

  4. insert_data: This method inserts a list of key-data row pairs into an existing table in the storage system.

  5. delete_data: This method deletes a list of keys and their corresponding data rows from an existing table in the storage system.

/// By implementing `StoreMut` trait,
/// you can run `INSERT`, `CREATE TABLE`, `DELETE`, `UPDATE` and `DROP TABLE` queries.
#[async_trait(?Send)]
pub trait StoreMut {
async fn insert_schema(&mut self, schema: &Schema) -> Result<()>;

async fn delete_schema(&mut self, table_name: &str) -> Result<()>;

async fn append_data(&mut self, table_name: &str, rows: Vec<DataRow>) -> Result<()>;

async fn insert_data(&mut self, table_name: &str, rows: Vec<(Key, DataRow)>) -> Result<()>;

async fn delete_data(&mut self, table_name: &str, keys: Vec<Key>) -> Result<()>;
}
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/storages/developing-custom-storages/store-traits/store/index.html b/docs/0.16.0/storages/developing-custom-storages/store-traits/store/index.html new file mode 100644 index 00000000..7b55de43 --- /dev/null +++ b/docs/0.16.0/storages/developing-custom-storages/store-traits/store/index.html @@ -0,0 +1,17 @@ + + + + + +Store | GlueSQL + + + + + +
+

Store

The Store trait is the most essential trait to implement for custom storage. Simply by implementing the Store trait, you can support SELECT queries in SQL. You may want to analyze and retrieve data from log files or external APIs using SQL. In this case, having only SELECT queries available is sufficient, and there might not be any need for data modification. In such scenarios, implementing GlueSQL's Store trait alone would be adequate.

Here are the four methods required to implement the Store trait:

  1. fetch_schema: This method is responsible for fetching a schema for a given table name. It returns an optional schema if the table exists.

  2. fetch_all_schemas: This method fetches all the schemas from the storage system. It returns a vector of schemas.

  3. fetch_data: This method fetches a specific data row from the storage system using the provided table name and key. It returns an optional data row if the key exists in the table.

  4. scan_data: This method is used to scan all the data rows in a table. It returns an iterator over the rows in the specified table.

pub type RowIter = Box<dyn Iterator<Item = Result<(Key, DataRow)>>>;

/// By implementing `Store` trait, you can run `SELECT` query.
#[async_trait(?Send)]
pub trait Store {
async fn fetch_schema(&self, table_name: &str) -> Result<Option<Schema>>;

async fn fetch_all_schemas(&self) -> Result<Vec<Schema>>;

async fn fetch_data(&self, table_name: &str, key: &Key) -> Result<Option<DataRow>>;

async fn scan_data(&self, table_name: &str) -> Result<RowIter>;
}
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/storages/developing-custom-storages/store-traits/transaction/index.html b/docs/0.16.0/storages/developing-custom-storages/store-traits/transaction/index.html new file mode 100644 index 00000000..10d42158 --- /dev/null +++ b/docs/0.16.0/storages/developing-custom-storages/store-traits/transaction/index.html @@ -0,0 +1,17 @@ + + + + + +Transaction | GlueSQL + + + + + +
+

Transaction

While transactions are often considered an essential feature for databases, GlueSQL treats transactions as an optional trait. Custom storage developers can choose whether or not to support transactions in their storage implementation. Transactions can be quite heavy and expensive in terms of performance.

If you're building a general-purpose OLTP database, transactions are a necessary feature. However, if you want to handle JSONL log files using SQL, transactions may be desirable, but not strictly necessary at the cost of significant performance degradation.

You can verify your Transaction trait implementation using the Test Suite. However, the Test Suite only provides logical tests for single-threaded environments. If you intend to support transactions in a concurrent environment, you'll need to write additional tests to verify your implementation. This allows different storage implementations to support various transaction isolation levels.

Currently, the SAVEPOINT feature is not supported, and only three methods are available: BEGIN (or START TRANSACTION), ROLLBACK, and COMMIT.

#[async_trait(?Send)]
pub trait Transaction {
async fn begin(&mut self, autocommit: bool) -> Result<bool>;

async fn rollback(&mut self) -> Result<()>;

async fn commit(&mut self) -> Result<()>;
}
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/storages/developing-custom-storages/using-test-suite/index.html b/docs/0.16.0/storages/developing-custom-storages/using-test-suite/index.html new file mode 100644 index 00000000..a6f1e3cb --- /dev/null +++ b/docs/0.16.0/storages/developing-custom-storages/using-test-suite/index.html @@ -0,0 +1,17 @@ + + + + + +Using the Test Suite | GlueSQL + + + + + +
+

Using the Test Suite

The GlueSQL Test Suite is a valuable tool for validating your custom storage implementation. By using the provided test sets, you can ensure that your storage implementation adheres to the required specifications and works as expected with GlueSQL.

To use the Test Suite, you will need to implement the Tester trait for your custom storage. A great reference for this process is the MemoryStorage implementation in the GlueSQL source code. Here's an example of how the MemoryStorage implementation looks like:

use {
async_trait::async_trait, gluesql_core::prelude::Glue, gluesql_memory_storage::MemoryStorage,
test_suite::*,
};

struct MemoryTester {
glue: Glue<MemoryStorage>,
}

#[async_trait(?Send)]
impl Tester<MemoryStorage> for MemoryTester {
async fn new(_: &str) -> Self {
let storage = MemoryStorage::default();
let glue = Glue::new(storage);

MemoryTester { glue }
}

fn get_glue(&mut self) -> &mut Glue<MemoryStorage> {
&mut self.glue
}
}

Once you have implemented the Tester trait, you can easily add the relevant test sets for the traits you have implemented in your custom storage. Here's how the MemoryStorage implementation adds the test sets:

generate_store_tests!(tokio::test, MemoryTester);

generate_alter_table_tests!(tokio::test, MemoryTester);

generate_metadata_table_tests!(tokio::test, MemoryTester);

generate_custom_function_tests!(tokio::test, MemoryTester);

The MemoryStorage example demonstrates the use of the four test sets from the Test Suite, indicating that it has implemented the Store, StoreMut, AlterTable, CustomFunction, CustomFunctionMut, and Metadata traits. However, you don't need to implement all Store traits for your custom storage. Instead, you can choose to implement only the traits that are relevant to your use case, and use the corresponding test sets from the Test Suite for validation.

The Test Suite provides test sets for the following traits:

  • generate_store_tests! - Tests for Store and StoreMut implementations. (Note that Store and StoreMut are required for all other test sets.)
  • generate_alter_table_tests! - Tests for the AlterTable trait implementation.
  • generate_custom_function_tests! - Tests for the CustomFunction and CustomFunctionMut trait implementations.
  • generate_index_tests! - Tests for the Index and IndexMut trait implementations.
  • generate_transaction_tests! - Tests for the Transaction trait implementation.
  • generate_metadata_table_tests! - Tests for the Metadata trait implementation.

Additionally, the Test Suite provides combined test sets for cases where you have implemented multiple optional traits:

  • generate_alter_table_index_tests! - Tests for the AlterTable, Index, and IndexMut trait implementations.
  • generate_transaction_alter_table_tests! - Tests for the Transaction and AlterTable trait implementations.
  • generate_transaction_index_tests! - Tests for the Transaction, Index, and IndexMut trait implementations.
  • generate_metadata_index_tests! - Tests for the Metadata, Index, and IndexMut trait implementations.

In summary, the GlueSQL Test Suite is an essential tool for validating your custom storage implementation. By using the provided test sets and the MemoryStorage implementation as an example, you can ensure your storage works correctly with GlueSQL and adheres to the necessary specifications.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/storages/intro/index.html b/docs/0.16.0/storages/intro/index.html new file mode 100644 index 00000000..c8c14725 --- /dev/null +++ b/docs/0.16.0/storages/intro/index.html @@ -0,0 +1,17 @@ + + + + + +Introduction | GlueSQL + + + + + +
+

Introduction

GlueSQL is not only suitable for use as a conventional database, but one of its key features is the ability for anyone to easily adapt SQL and the AST Builder to their desired file or storage system. This adaptability is achieved through the following topics covered in this section:

Supported Storages

GlueSQL provides a variety of reference storages out of the box, ranging from simple in-memory storage to key-value databases, log file-based storage like JSON & JSONL, and even Web Storage and IndexedDB supported by web browsers.

Developing Custom Storages

GlueSQL offers an easy-to-understand and implement interface for custom storage development. By implementing the corresponding interface, developers can have SQL and the AST Builder automatically support their custom storage.

Verification of custom storage implementation is also straightforward using GlueSQL's test-suite, which allows developers to easily test their implementation and fix any issues found during the process. With a line coverage of nearly 99% in the GlueSQL project's core code, custom storage developers can complete the development and verification process simply by passing all the test-suite cases.

Exploring the Storages Section

In the Storages section, you will find detailed information about the reference storages currently supported by GlueSQL, as well as guidelines for developing custom storages and what needs to be done to implement them.

Together, these resources make it easy to utilize and adapt GlueSQL for a variety of storage systems.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/storages/supported-storages/composite-storage/index.html b/docs/0.16.0/storages/supported-storages/composite-storage/index.html new file mode 100644 index 00000000..30e97e82 --- /dev/null +++ b/docs/0.16.0/storages/supported-storages/composite-storage/index.html @@ -0,0 +1,17 @@ + + + + + +Composite Storage | GlueSQL + + + + + +
+

Composite Storage

Introduction

CompositeStorage is a special type of Storage. It does not possess any real storage implementation itself. Instead, it offers a powerful capability - the ability to bundle together multiple existing storages. For instance, with CompositeStorage, you can bundle JsonStorage and SledStorage together for simultaneous use. This means you can perform JOIN operations across two distinct storages. You can even read and analyze JSON log files, and directly insert the data into SledStorage.

Unified Interface across Different Storages

In fact, the Javascript (Web) GlueSQL interface already utilizes CompositeStorage. Take a look at this:

CREATE TABLE Mem (mid INTEGER) ENGINE = memory;
CREATE TABLE Loc (lid INTEGER) ENGINE = localStorage;
CREATE TABLE Ses (sid INTEGER) ENGINE = sessionStorage;
CREATE TABLE Idb (iid INTEGER) ENGINE = indexedDB;

SELECT
mid, lid, sid, iid
FROM Mem
JOIN Loc
JOIN Ses
JOIN Idb;

You can create tables using four different storages and perform operations like JOIN using SQL! All you have to do is specify the ENGINE during CREATE TABLE. That's all it takes.

Potential and Future Plans

CompositeStorage can be immensely useful in various applications. At present, GlueSQL might not offer a plethora of reference storages. However, plans are in place to support a diverse range of storages in the future. These include log files like CSV and Parquet, and even NoSQL databases like Redis and MongoDB. They're not exceptions; they can fully provide an SQL interface via GlueSQL.

In addition, just as you would use an ORM to handle multiple different SQL databases with the same interface, plans are in place to use existing SQL databases in a similar way as storages in GlueSQL. Once all these plans come to fruition, you will be able to implement your data pipelines very simply.

Moving data from Redis to MongoDB, or from MySQL to Redis will be a breeze - just by specifying the ENGINE using the same GlueSQL SQL or AST Builder.

Limitations and Considerations

CompositeStorage might sound like a cure-all solution, but it does have its limitations. As it combines different data storages, certain boundaries exist. Transactions, for instance, are a major one. Each storage may have different transaction support and methods. Therefore, it is not advisable to use CompositeStorage for operations that require transactions. It's more suitable for moving or analyzing data across different storages.

Summary

In conclusion, CompositeStorage is an exciting and powerful feature of GlueSQL, enabling users to combine and use different storage types seamlessly. However, users should also be aware of its limitations, such as transaction handling. Despite these constraints, the potential and flexibility offered by CompositeStorage make it a compelling choice for a variety of data manipulation tasks, especially when working with diverse storage types.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/storages/supported-storages/csv-storage/index.html b/docs/0.16.0/storages/supported-storages/csv-storage/index.html new file mode 100644 index 00000000..dd0782dc --- /dev/null +++ b/docs/0.16.0/storages/supported-storages/csv-storage/index.html @@ -0,0 +1,17 @@ + + + + + +CSV Storage | GlueSQL + + + + + +
+

CSV Storage

Introducing CSVStorage: a utility to process *.csv files, enabling SQL-like query operations such as SELECT, INSERT, and UPDATE.

Key Features:

  1. SQL Queries on CSV: Directly parse and operate on *.csv files using familiar SQL query operations.

  2. Optional Schema Support: An associated schema can be provided for each CSV file. For instance, for a data file named Book.csv, its corresponding schema file should be named Book.sql.

    • If an associated schema file is found, it will be read and applied.
    • In the absence of a schema file, the first row of the data file will be treated as column headers and all column types will default to TEXT.
  3. Type Info File for Schemaless Data: An auxiliary types file (*.types.csv) can be used to support data type recognition for schemaless data.

    • For a CSV data file named Book.csv, its corresponding types file will be Book.types.csv.
    • The types file will have a 1:1 mapping with the CSV data file entries, specifying the data type for each entry in alignment with the GlueSQL conventions.
+ + + + \ No newline at end of file diff --git a/docs/0.16.0/storages/supported-storages/idb-storage/index.html b/docs/0.16.0/storages/supported-storages/idb-storage/index.html new file mode 100644 index 00000000..a30823a3 --- /dev/null +++ b/docs/0.16.0/storages/supported-storages/idb-storage/index.html @@ -0,0 +1,17 @@ + + + + + +IndexedDB Storage | GlueSQL + + + + + +
+

IndexedDB Storage

Introduction

IndexedDB, now easily handled just like SQL with GlueSQL - this is truly magical! For those who have directly used IndexedDB before, it's well known that it's not the most intuitive type of database to interact with. Even the MDN IndexedDB introduction page acknowledges this complexity, stating:

Note: IndexedDB API is powerful, but may seem too complicated for simple cases. If you'd prefer a simple API, try libraries in See also section that make IndexedDB more programmer-friendly.

In particular, version management in IndexedDB might be a somewhat unfamiliar concept for regular database users. But worry not, GlueSQL has innovatively handled these intricacies, freeing you from the need to grapple with such complexities. You can just use SQL, and everything will work as expected.

Behind the Scenes

When there are schema changes, like a CREATE TABLE query, GlueSQL increases the IndexedDB version and handles it internally. The data to be stored is also converted into a JSON format for storage. Thanks to this, you can easily check how GlueSQL is handling data by using the IndexedDB viewer in the web browser's developer console.

Compatibility and Use

Currently, only the Store and StoreMut traits are implemented and supported. You can use it in both JavaScript (Web) and Rust WebAssembly environments.

When using it in a web environment, just set the ENGINE to indexedDB in the CREATE TABLE query.

CREATE TABLE Item (id INTEGER, name TEXT) ENGINE = indexedDB;

Just by using it like this, GlueSQL will operate based on the IndexedDB storage.

Summary

In conclusion, if you are seeking for a way to interact with IndexedDB without the usual complexity, GlueSQL is a fantastic choice. It provides a clear, SQL-based approach to managing data, making IndexedDB much more accessible and user-friendly.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/storages/supported-storages/json-storage/index.html b/docs/0.16.0/storages/supported-storages/json-storage/index.html new file mode 100644 index 00000000..2e28ba8f --- /dev/null +++ b/docs/0.16.0/storages/supported-storages/json-storage/index.html @@ -0,0 +1,19 @@ + + + + + +JSON Storage | GlueSQL + + + + + +
+

JSON Storage

Introduction

The JSON Storage system is comprised of two types of files: Schema file(optional) and Data file. The Schema file is written in Standard SQL and is responsible for storing the structure of the table. The Data file contains the actual data and supports two file formats: *.json and *.jsonl. This document provides detailed examples of how to create schema and read/write data using the Json Storage system. While it supports all DML features, it is particularly specialized for SELECT and APPEND INSERT. For further information, please refer to the Limitations section.

Structure

JSON Storage is based on two types of files: Schema and Data. The Schema file contains the definition of the structure of the data, while the Data file contains the actual data.

gluesql> CREATE TABLE User (
id INT,
name TEXT
)
$ ls -l

User.sql # Schema file
User.jsonl # Data file

Schema File

The schema definition is saved in a file named {TABLE_NAME}.sql using standard SQL. For example, if the table name is User, then the schema file will be named User.sql.

--! User.sql
CREATE TABLE User (
id INT,
name TEXT,
);

Schemaless Table

A schemaless table is optional, and if there is no corresponding {TABLE_NAME}.sql file, the table is schemaless. A schemaless table can save any data regardless of column name and data type.

gluesql> CREATE Table User;
$ ls -l

User.jsonl

Data File

JSON Storage saves data in two types of data files: *.jsonl (default) and *.json.

*.jsonl File Format

The *.jsonl file format is a file containing one JSON object per line. For example:

{"id": 1, "name": "Glue"}
{"id": 2, "name": "SQL"}

*.json File Format

The *.json file format supports two different formats:

  1. Array of JSON
[
{
"id": 1,
"name": "Glue"
},
{
"id": 2,
"name": "SQL"
}
]
  1. Single JSON
{
"name": "GlueSQL"
"keywords": ["Database, Rust"]
"stars": 999999
}

Examples

Read Existing JSON/JSONL Schemaless Files

  1. Locate your JSON/JSONL schemaless files in the data path. Here, we use ./data.
$ ls -rlt ./data

User.json
LoginHistory.jsonl

Keep in mind that if there are no *.sql files, the data is considered schemaless, meaning that the number of columns in each row may vary.

//! User.json
[
{
"id": 1,
"name": "Alice",
"location": "New York"
},
{
"id": 2,
"name": "Bob",
"language": "Rust"
},
{
"id": 3,
"name": "Eve"
}
]
//! LoginHistory.jsonl
{"timestamp": "2023-05-01T14:36:22.000Z", "userId": 1, "action": "login"}
{"timestamp": "2023-05-01T14:38:17.000Z", "userId": 2, "action": "logout"}
{"timestamp": "2023-05-02T08:12:05.000Z", "userId": 2, "action": "logout"}
{"timestamp": "2023-05-02T09:45:13.000Z", "userId": 3, "action": "login"}
{"timestamp": "2023-05-03T16:21:44.000Z", "userId": 1, "action": "logout"}
  1. Read with GlueSQL JSON Storage
let path = "./data/";
let json_storage = JsonStorage::new(path).unwrap();
let mut glue = Glue::new(json_storage);

glue.execute("
SELECT *
FROM User U
JOIN LoginHistory L ON U.id = L.userId;
");
actionidlanguagelocationnametimestampuserId
login1New YorkAlice2023-05-01T14:36:22.000Z1
logout1New YorkAlice2023-05-03T16:21:44.000Z1
logout2RustBob2023-05-01T14:38:17.000Z2
logout2RustBob2023-05-02T08:12:05.000Z2
login3Eve2023-05-02T09:45:13.000Z3

Create Schema Table

  1. Create Table
let path = "./data/";
let json_storage = JsonStorage::new(path).unwrap();
let mut glue = Glue::new(json_storage);

glue.execute("
CREATE TABLE Account (
accountId INT NOT NULL,
accountOwner TEXT NOT NULL,
accountType TEXT NOT NULL,
balance INT NOT NULL,
isActive BOOLEAN NOT NULL
);
");
$ ls -l

Account.sql
Account.jsonl
  1. Verity Schema file
--! Account.sql
CREATE TABLE Account (
accountId INT NOT NULL,
accountOwner TEXT NOT NULL,
accountType TEXT NOT NULL,
balance INT NOT NULL,
isActive BOOLEAN NOT NULL
);
  1. Insert data
glue.execute("
INSERT INTO Account VALUES
(10001, 'John Smith', 'Checking', 5000, true),
(10002, 'Jane Doe', 'Savings', 10000, true),
(10003, 'Robert Johnson', 'Checking', 2500, false),
(10004, 'Alice Kim', 'Savings', 7500, true),
(10005, 'Michael Chen', 'Checking', 10000, true);
");
  1. Select data
glue.execute("SELECT * FROM Account;");
accountIdaccountOwneraccountTypebalanceisActive
10001John SmithChecking5000TRUE
10002Jane DoeSavings10000TRUE
10003Robert JohnsonChecking2500FALSE
10004Alice KimSavings7500TRUE
10005Michael ChenChecking10000TRUE
  1. Verify Data file
//! Account.jsonl
{"accountId":10001,"accountOwner":"John Smith","accountType":"Checking","balance":5000,"isActive":true}
{"accountId":10002,"accountOwner":"Jane Doe","accountType":"Savings","balance":10000,"isActive":true}
{"accountId":10003,"accountOwner":"Robert Johnson","accountType":"Checking","balance":2500,"isActive":false}
{"accountId":10004,"accountOwner":"Alice Kim","accountType":"Savings","balance":7500,"isActive":true}
{"accountId":10005,"accountOwner":"Michael Chen","accountType":"Checking","balance":10000,"isActive":true}

Limitation

JSON Storage is capable of supporting a variety of operations, including SELECT, INSERT, DELETE, and UPDATE.
+However, its design primarily emphasizes SELECT and APPEND INSERT functionality.
+It's important to note that if you perform DELETE, UPDATE, or INSERT in the middle of the rows, it can cause the internal rewriting of all the rows, which can lead to a decrease in performance.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/storages/supported-storages/memory-storage/index.html b/docs/0.16.0/storages/supported-storages/memory-storage/index.html new file mode 100644 index 00000000..1adaf651 --- /dev/null +++ b/docs/0.16.0/storages/supported-storages/memory-storage/index.html @@ -0,0 +1,17 @@ + + + + + +Memory Storage | GlueSQL + + + + + +
+

Memory Storage

MemoryStorage is a foundational storage option designed for in-memory, non-persistent data. Despite its simplicity, it is robust enough for use in production environments.

A key aspect of MemoryStorage is not only its functionality but also its role as an exemplary case showcasing how simple it is to develop custom storage in GlueSQL. It provides a practical demonstration of what a minimalistic, yet fully functional storage interface can look like in GlueSQL.

MemoryStorage is accessible across multiple environments, including Rust, Rust (WASM), JavaScript (Web), and Node.js.

The storage interface is implemented with the following traits: Store, StoreMut, AlterTable, CustomFunction, CustomFunctionMut, and Metadata.

Consider the Rust code structure for MemoryStorage:

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Item {
pub schema: Schema,
pub rows: BTreeMap<Key, DataRow>,
}

#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct MemoryStorage {
pub id_counter: i64,
pub items: HashMap<String, Item>,
pub metadata: HashMap<String, HashMap<String, Value>>,
pub functions: HashMap<String, StructCustomFunction>,
}

This structure defines the Item and MemoryStorage structs. Item struct holds the schema and rows, while MemoryStorage struct consists of id_counter (to keep track of the row IDs), items (to store the actual data), metadata (to keep metadata), and functions (to store custom functions).

Below are the implementations of the Store and StoreMut traits for MemoryStorage:

#[async_trait(?Send)]
impl Store for MemoryStorage {
// Code for fetching schemas and data
}

#[async_trait(?Send)]
impl StoreMut for MemoryStorage {
// Code for manipulating schemas and data
}

The Store trait implementation provides methods for fetching all schemas, fetching a specific schema, fetching data from a specific table with a given key, and scanning all data from a particular table.

On the other hand, the StoreMut trait implementation provides methods for inserting a new schema, deleting an existing schema, appending data to a table, inserting data into a table with a specific key, and deleting data from a table with given keys.

In summary, the MemoryStorage structure in GlueSQL is a straightforward yet powerful tool that elegantly showcases how simple it is to create a custom storage system. It's a testament to the power and flexibility of GlueSQL's design and the ease of implementing robust storage solutions with it.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/storages/supported-storages/parquet-storage/index.html b/docs/0.16.0/storages/supported-storages/parquet-storage/index.html new file mode 100644 index 00000000..ed58befd --- /dev/null +++ b/docs/0.16.0/storages/supported-storages/parquet-storage/index.html @@ -0,0 +1,21 @@ + + + + + +Parquet Storage | GlueSQL + + + + + +
+

Parquet Storage

Introduction

The Parquet Storage Extension empowers users to interact with Parquet files through SQL statements efficiently, making the reading and writing of Parquet files straightforward and user-friendly.

Structure

The extension is designed to handle files with a .parquet extension and performs read and write operations in the path specified by the user. It provides flexibility for creating files with or without a predefined schema using the DDL statement, adjusting to user needs effectively.

  • Schema or Schema-less Files Creation: +Users can create either schema or schema-less files using the table name defined in the DDL statement. It adjusts the Parquet's schema and field information to align with GlueSQL's constructs, enabling efficient data querying processes.

  • Data Querying: +When querying data, the extension converts Parquet's schema and field information to GlueSQL's corresponding constructs. This conversion allows users to perform data queries seamlessly, leveraging the uniformity in schema and field information representation.

  • Data Modification: +Any changes in the data are reverted from GlueSQL's schema and field information back to Parquet's original constructs before being written back to a .parquet file. This bidirectional conversion ensures data integrity and consistency between the two formats during read and write operations.

Schema File

With this extension, you can create new schemas using DDL statements and modify data using DML statements, ensuring seamless interaction with Parquet files.

Examples

Note: {} denotes a placeholder that you must replace with actual values.

To start interacting with the Parquet extension, use the following command in your CLI:

./gluesql -p {workspace path} -s parquet

Creating a Table

gluesql> CREATE TABLE food (name TEXT);
Table created

At this point, you can verify the creation of the food.parquet file in the specified path (./).

Inserting Data and Querying

INSERT INTO food VALUES('sushi'), ('steak');

SELECT * FROM food;
2 row inserted

| name |
|-------|
| sushi |
| steak |

Updating Data and Querying

UPDATE food SET name = 'Nigiri Sushi' WHERE name='sushi';
SELECT * FROM food;
1 row updated

| name |
|--------------|
| Nigiri Sushi |
| steak |

Deleting Data and Querying

DELETE name FROM food WHERE name = 'steak';
SELECT * FROM food;
1 row deleted

| name |
|--------------|
| Nigiri Sushi |

Remember to replace placeholders with the appropriate values and paths when using the commands, and follow the structured steps for effective interaction with Parquet files using GlueSQL.

In rust.

let path = "./";
let parquet_storage = ParquetStorage::new(path).unwrap();
let mut glue = Glue::new(parquet_storage);
glue.execute("CREATE TABLE food (name TEXT);")
.await
.unwrap();

glue.execute("INSERT INTO food VALUES('sushi'), ('steak');")
.await
.unwrap();

glue.execute("UPDATE food SET name = 'Nigiri Sushi' WHERE name='sushi';")
.await
.unwrap();

glue.execute("DELETE name FROM food WHERE name = 'steak';")
.await
.unwrap();

glue.execute("SELECT * FROM food;").await.unwrap();

Schemaless File Interaction

Parquet files inherently require a predefined schema. When creating tables without an explicit schema (schemaless tables), this extension establishes a temporary schema utilizing the Map datatype for the parquet file. This functionality ensures that even schemaless instances can process queries and modifications effectively.

Implications

  • Ease of Interaction: The temporary schema creation allows users to interact with schemaless parquet files with ease, facilitating various operations such as data retrieval and modifications effectively.

  • Structured Interaction: The use of the Map datatype as a temporary schema enables structured interaction with schemaless parquet files, ensuring a smooth user experience.

Examples

Creating Schemaless Table, Inserting, and Querying Data

CREATE TABLE Logs;
INSERT INTO Logs VALUES
('{ "id": 1, "value": 30 }'),
('{ "id": 2, "rate": 3.0, "list": [1, 2, 3] }'),
('{ "id": 3, "rate": 5.0, "value": 100 }');
SELECT id, rate, list FROM Logs WHERE id = 2;
Table created
3 rows inserted

| id | rate | list |
|----|------|---------|
| 2 | 3 | [1,2,3] |

Updating Data and Querying

UPDATE Logs SET list='[5,6]' where id = 2;
SELECT id, rate, list FROM Logs WHERE id = 2;
1 row updated
| id | rate | list |
|----|------|-------|
| 2 | 3 | [5,6] |

Deleting Data and Querying

Caution: Deleting data in a schemaless table removes all the data within it

DELETE from Logs where id = 2;
SELECT id, rate, list FROM Logs WHERE id = 2;
1 row deleted
| id | rate | list |

In rust.

let path = "./";
let parquet_storage = ParquetStorage::new(path).unwrap();
let mut glue = Glue::new(parquet_storage);
glue.execute("CREATE TABLE Logs;")
.await
.unwrap();

glue.execute("INSERT INTO Logs VALUES
('{ "id": 1, "value": 30 }'),
('{ "id": 2, "rate": 3.0, "list": [1, 2, 3] }'),
('{ "id": 3, "rate": 5.0, "value": 100 }');")
.await
.unwrap();

glue.execute("UPDATE Logs SET list='[5,6]' where id = 2;")
.await
.unwrap();

//Caution: Deleting data in a schemaless table removes all the data within it
glue.execute("DELETE from Logs where id = 2;")
.await
.unwrap();

glue.execute("SELECT * FROM food;").await.unwrap();

Limitations

  1. For Parquet files storing data with parquet::record::api::Field::MapInternal, errors are encountered if the key information utilizes a data type other than string as the key. +This is attributed to the fact that GlueSQL's HashMap is of type <String, Value>, hence, limiting the use of other data types as keys.

  2. The interface for reading data in columnar units is currently not supported by GlueSQL, which might result in suboptimal read and write performance.

  3. Incompatibility with Parquet Physical Types:

GlueSQL currently lacks support for certain Parquet physical types, specifically INT96 and FIXED_LENGTH_BYTE_ARRAY. As a result, when executing data modification queries like INSERT or UPDATE on Parquet files, the data type for these columns will be transformed. Columns originally in the INT96 type will be changed to GlueSQL's Int128, and those in FIXED_LENGTH_BYTE_ARRAY will be converted to GlueSQL's Bytea type. This conversion can have implications on data consistency and might necessitate additional transformations when interacting with other systems or tools that expect the original Parquet physical types.

Conclusion

Despite certain limitations, this extension significantly simplifies interactions with Parquet files, making GlueSQL a more versatile tool by supporting a popular columnar storage file format.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/storages/supported-storages/shared-memory-storage/index.html b/docs/0.16.0/storages/supported-storages/shared-memory-storage/index.html new file mode 100644 index 00000000..7a0dfde2 --- /dev/null +++ b/docs/0.16.0/storages/supported-storages/shared-memory-storage/index.html @@ -0,0 +1,17 @@ + + + + + +Shared Memory Storage | GlueSQL + + + + + +
+

Shared Memory Storage

SharedMemoryStorage is a storage option designed to provide more comfortable usage of MemoryStorage in concurrent environments. Although it doesn't operate in parallel, it makes accessing the same data from multiple threads simultaneously more convenient.

The basic structure of SharedMemoryStorage is straightforward. It wraps the MemoryStorage with a read-write lock (RwLock) and an atomic reference count (Arc):

#[derive(Clone, Debug)]
pub struct SharedMemoryStorage {
pub database: Arc<RwLock<MemoryStorage>>,
}

This structure allows you to clone the storage instance and use it effortlessly across multiple threads. Regardless of how many times the storage is cloned, all storage instances will refer to the same data.

Here's an example of how to use SharedMemoryStorage in a concurrent environment:

use gluesql_core::prelude::{Glue, Payload, Value};

async fn concurrent_access() {
let storage = SharedMemoryStorage::new();

let mut glue = Glue::new(storage.clone());
glue.execute("CREATE TABLE Thread (id INTEGER);").unwrap();

let thread_1 = tokio::spawn({
let storage = storage.clone();
async {
let mut glue = Glue::new(storage);
glue.execute("INSERT INTO Thread VALUES(1)").unwrap();
}
});

let thread_2 = tokio::spawn({
let storage = storage.clone();
async {
let mut glue = Glue::new(storage);
glue.execute("INSERT INTO Thread VALUES(2)").unwrap();
}
});

let _ = tokio::join!(thread_1, thread_2);

let actual = glue.execute("SELECT * FROM Thread").unwrap();
let expected = vec![Payload::Select {
labels: vec!["id".to_owned()],
rows: vec![vec![Value::I64(1)], vec![Value::I64(2)]],
}];
assert_eq!(actual, expected);
}

The concurrent_access function above illustrates how to concurrently insert data into the same table from different threads. After inserting data from two separate threads, we can confirm that the inserted data is correctly stored by executing a SELECT statement.

SharedMemoryStorage is primarily intended for convenience rather than performance when dealing with multiple threads. As you can see from the structure, placing a read-write lock (RwLock) on the entire database is not recommended for performance reasons when handling data concurrently from multiple threads. Therefore, it's best to use SharedMemoryStorage or MemoryStorage depending on the situation.

SharedMemoryStorage is only available in the Rust environment, and its implementation of the Store trait is identical to that of MemoryStorage.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/storages/supported-storages/sled-storage/index.html b/docs/0.16.0/storages/supported-storages/sled-storage/index.html new file mode 100644 index 00000000..01a12e52 --- /dev/null +++ b/docs/0.16.0/storages/supported-storages/sled-storage/index.html @@ -0,0 +1,17 @@ + + + + + +Sled Storage | GlueSQL + + + + + +
+

Sled Storage

SledStorage is currently the representative persistent data storage for GlueSQL. As the name suggests, it's a storage option based on the Sled key-value embedded database built in Rust (Sled on Github).

SledStorage can only be used in a Rust environment. It is the only storage among those currently supported by GlueSQL that implements all Store traits, from non-clustered indexes to transactions. If you're looking for a basic storage to handle and store data in a Rust environment, SledStorage is an excellent choice.

How to use

You can simply create a SledStorage instance using a path, as shown below:

use {
gluesql::{prelude::Glue, sled_storage::SledStorage},
sled_storage::sled,
std::convert::TryFrom,
};

fn main() {
let storage = SledStorage::new("data/temp").unwrap();
let mut glue = Glue::new(storage);

let sqls = "
CREATE TABLE Glue (id INTEGER);
INSERT INTO Glue VALUES (100), (200);
";

glue.execute(sqls).unwrap();
}

If you want to use the Sled that SledStorage uses directly with a specific configuration, you can do so as follows:

let config = sled::Config::default()
.path("data/using_config")
.temporary(true)
.mode(sled::Mode::HighThroughput);

let storage = SledStorage::try_from(config).unwrap();
let mut glue = Glue::new(storage);

Things to Know About Transactions

The implementation of transactions in SledStorage manages not only data but also indexes and schema information based on snapshots. For example, if you use the following commands:

BEGIN;

CREATE TABLE Foo;
INSERT INTO Foo VALUES (1);

ROLLBACK;

The above usage will result in a rollback of even the contents regarding the Foo table. The transaction isolation level is repeatable read (snapshot isolation).

By default, there is a timeout for Transactions. The default is set to one hour, but you can modify the value or remove the timeout if desired.

storage.set_transaction_timeout(Some(1000)); // 1 sec
storage.set_transaction_timeout(None); // no timeout

Summary

If you're looking for a storage to handle data for general purposes in a Rust environment, SledStorage would be your go-to choice. It offers all the necessary features of a database system, such as managing non-clustered indexes, handling transactions, and maintaining persistent storage. Additionally, its snapshot-based transaction model ensures consistency and reliability, making it an excellent choice for applications requiring persistent data storage.

+ + + + \ No newline at end of file diff --git a/docs/0.16.0/storages/supported-storages/web-storage/index.html b/docs/0.16.0/storages/supported-storages/web-storage/index.html new file mode 100644 index 00000000..ee646ca8 --- /dev/null +++ b/docs/0.16.0/storages/supported-storages/web-storage/index.html @@ -0,0 +1,17 @@ + + + + + +WebStorage (local & session) | GlueSQL + + + + + +
+

WebStorage (local & session)

WebStorage - yes, the localStorage and sessionStorage you're familiar with. With GlueSQL, you can use SQL to interact with these storages!

WebStorage serves as a data storage that supports READ & WRITE operations. As GlueSQL can be ported to any place where READ & WRITE are possible, it can utilize WebStorage as one of its storage systems.

WebStorage provides a very simple and easy-to-use interface. All you need to do is read and write data using a string key. If you need to manage more structured data, you can use GlueSQL.

WebStorage can be used in JavaScript (Web) environments and Rust WebAssembly environments.

Usage

The way to use it is no different from using other storages.

import { gluesql } from 'gluesql';

async function run() {
const db = await gluesql();

const result = await db.query(`
CREATE TABLE Foo (id INTEGER, name TEXT) ENGINE = localStorage;
INSERT INTO Foo VALUES (1, 'hello'), (2, 'world');
SELECT * FROM Foo;
CREATE TABLE Bar ENGINE = sessionStorage;
INSERT INTO Bar VALUES ('{ "a": "schemaless", "b": 1024 }');
SELECT * FROM Bar;
`);

console.log(result);
}

Simple, isn't it?

Things to keep in mind

In the case of WebStorage, depending on the web browser, there is usually a size constraint of about 10MB for data storage. Even when using GlueSQL, you should keep in mind that it is used within these restrictions.

Summary

To sum up, WebStorage is a handy feature that allows you to manipulate localStorage and sessionStorage with SQL in a browser environment. It's simple, easy to use, and can handle structured data which makes it an ideal choice for lightweight web applications.

However, due to storage limitations, it's not suitable for large-scale data handling. Remember to consider these limitations when choosing your storage options in GlueSQL. Even with these constraints, it serves as a great tool for managing and interacting with your browser's storage in a structured way using SQL.

+ + + + \ No newline at end of file

5pdNdb0UbSj_ZZwSR6bnqgGVFnFZ6XKHXg*NBJr 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 z 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 literal 0 HcmV?d00001 diff --git a/docs/0.16.0/assets/images/blog-test-driven-documentation-insert-errorcase-1be5ced205cee0d2eeb56af1591440ac.jpg b/docs/0.16.0/assets/images/blog-test-driven-documentation-insert-errorcase-1be5ced205cee0d2eeb56af1591440ac.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8f3fd614a88fb08f7d59f8f92df91367810cc462 GIT binary patch literal 67868 zcmeFZc{r5++dn)~))0{plZeVzvSph}wuC4Yp|XXTY#EH1O2{5Uh^g#ZCi`x(M=|zg zEMu(MXUG_4`(2;=zJK@g9QScN&vD<+^Vjnn-^;uYf6O)4^*-O%xxCKTdA={^1al5_ z;c#1yl(9ftXVuJrL`WBmaDW<0$Ys#&PV}(WA$>*xA`Qj&mJ9&dtTm&BH5j zf`^x%mz(>3$WjPuwrPC*`S9>M?d!TbT@ z=U{olHqOd&4s?W{g_WO$*#QEBKrF|A+5R)(|2SBV0CQwx=iubx22Q9x0Xo9M%6jA| z>p!yw&JG2>2OZ@7sSIY^Yg`qcLgC)X+A(;}kh zWn?d0yriP4rmk^KQ}33(fuWJ{?R)pFtZg1Vv~_ZJadmsy)$#;XLUd(f&=c|DIrP{vS#9pMw1# za^XP7Sy_OG$I1_afav$WMqdE^Yy5wC4Hi@r;vD(lTJu*4beryMkzrNhD*w>7Y7DF_ ztnQd_uNzP5@w(G1QsU3nAFujVevMuTaExVw_^QAs`FK4XG>Kzb^I&BSWQBKi2&`Y?0#cqsOH*XuUPu?Me2aoXIH(g z+(e3X_5H64vcdx&d(1AGxB}~7d_!OGF3Z1-pmoF`n9Ige(}$8dM=0cM>G$HrxGx_x z)@)2JyS;>UUCovoD4el>F8*B5=6oK_o~T$mpRRqi05;xU%aD#*j5n1Sw|ZmJ;g9{8 zFXTH{#%rL_+80peUl;J*;*ohgLXD9A zq=+pzzS5O>Wb8$Nh(6Oj*AN$|QDKSL-=Cb`(~tfLscYff>; zhGG6%Yx6Nd;o>MJ=uBC68$yk^olsR-1aop2q8S#*N1P1Goiz;Lc)=pqq9%2gzsv7u zfva4ON3_Ud-RH1+U*x&;PMG`)u1-v@ACUJqpn?h*hls=I+h7J)bF_k>}mPZO?2l^B+H^Mkg za*bT@l2EW~Z|Fy%S1l{$19A2vftRn{i(nZ@kv?%_qc_xg{hAUQwOq4!#=a4?@e)`D7(FHVH0kJzq1tRv0vv2sc`3DK@lfmBzmVmkLb~yM=F+t9D>!-E@m-7R= z7bEfYFKcW>PG4KK&l6V!w8z>lO4}j_rf!I`8Q=31=eu1ywc_Yua}jzpNYY@%SJ3%A zo4Mtsv@nJw#b*9|Y3F!2+%$)hft%^LXPSfWe3@7;!qq2sg7;c$PH33Z=YMzkOEe#n zNh|*N=2ui_%f&&Os^BEQxFuQ3Pf_#j@f*-~m9o@@>9q@JT_SXoo%n11RAGZ#1TB;> z<7tVo?8RC}tspJSx2BOS4q;ZVrfty|axed1#*#WFC{{ulLkS@kch1TV%R{PF#idN@ znrkc1Cdze-Jm$UDWvHVS(^u{Lr(7dV8O3Rw&Vb|)K9h|wERqd;eF36VM+&2Cf&bO_J`h1Qjb+EvtO7>5H$_HOUSJrDx0~w(RG<`#Mx#*SCg2Uuz+P-cMvBXmD7zXvNiS! z64S-bD8KIxBqomQlxI-F?8@n{8D}~bBZJ{u{?oZhw#|&fxqUj#;mN(fPolfFGdd@I zXTWxFar#$X2{^pGzMiNQRa#x?nNVf-9Of;_{>t{E(4&jmY+bw>s$WRZ1;a4JF^a3w z3Ch9)M#s?kdOMXms{FV}N=mxTbEC~cu}@C%)dx~k*>zi`FeV7PDasdVo4fD8(>z*M z@_gyNQACJ{lE;~m$zmJs#?!%={xb@)QQAF&8 z?u?RE z4Bha#(PWdM4Vrl#J%e9LJ>?9;IO+0lW4S2%ARS&gSgZD}XPD~R)GdT7+kVM?sna?nMU=bA9Wd=$9<O`~POE-E+7ca+_4lBd!DX?)bFv#%<(g7P3A|rD<{#2`q-U(*D3ZnV_S7 zOi&^iIODAs2~j&+W&9V+f_>(Ol)Jykzb;f<>E(ABhiNxAQ&7*!zFB~2jFJIEmG$L4u<#SH6`MiH& z;ag;xK?NongI}!LRa>sUa6dGVnu=H72Y->^1SEY8=O*n(D`-RVVZZeY9d1k3sFT%C z4c=LtyO4B?i*vIsHi`XS^q~w!f(e={0JG49iH6;?yr@=9?ck%Lov~OSx95FJoaX{q zMg(3af!}K!+*mUWO`%%C^+*zcKRo)^KE$jsT{TosZ-~&)9GiG9??<@n^Z4+v?^vo; zW|F`7gVKAo{hLaip`DY|0OLIy8s_&#%UNXWbzL_2wJ}BiOeRRwu+T%TqvZSQsfw9z zm*>zQqn-M1oSx~1+q|bx8C)~OcD><6388^%{K+*fKT)jcLp!&@tQZZN6vTE1Ns)2f zzz{L>EA1G5SV5Pl4kl_ZGt{(1pnuEoifzX^L!PBKEN+VUD_G7h-nBU<=oz$}(E+J( z{fOsuPU<$##tp4euN#ZPGJhwgZ2t5$KK@yGap_L_Q6F2X+PAjY?24LMk3ZRnXJ)z9 ziQ9`Ch>wVVu&~`iZL8yP*sR^H?+v48UF)i2)qds~I=^VFpGx^DTX=RnZ`jF;RP5w^ zUE^?;p&yS=>ZpM#{>hhLy^ z$O+7X8%-%;a=YD@{=3b~V+^t}b1$)R^9m^Mow#~gHxu-Fe8p|Ulc1wDFTCkRvS}0j zK2zX%=ulhmyRN7G(U+saLQ*euzsXesI^YMJvY@b1@4zr~-BB)=W%5*N%1hF@luCbj zxv*CyZnbW|Eg_mwg8dyITvW2kaSWWrZD<>kWUWHeRp{cV6^fJ+*$D`Oxv*qLyXO8* zc1sT(!vwjrURET_3h(=iRug z(`jUNKmz0hW5D4Aj$9D8|<>n{Ts(^{(v{op5myDVPegN zG!JB(YC#Kov0cu|gXH@dPwInhhzmB_r?)W$t`l??yeY5$f$`Xy@@v4C9PI10!vsOv zzr>5}r;;;vp}P#sZ=(6Dmb1fF)iu`ho&)hQ`j3f5#<`m8< zpZ22mPW+f}38hzK9)lw>mB?0W5;CG1b<)v8&*IH+?`T=+Vx-enPsa;MZ10smPbR4K z4EntJX}C!h4>d|&e#r$`d*=_V2iMS_A#>mGJ02Ct32*Fy@x7R8t@{z5`W5JFO55L` zG%phrf}jU#E$b*1L?`4sUppSBH}{Rw-qC=KDhaq+IQ{Uz)^xP##m4oI8cFQe4&sB* zgUDB?BQzbVCQYlB2#s*VGz>qfOI^W^EXJ(_CRUgT-nthLItXTQU;#|OhzUxzN?^37 zp?Wo`0u99>6;&_Y5ylKRRX&9F&}e~DANr>pQEH((98EK&-hjI#wJB+=2G`^jnuTo# z$px1G6elgS>Gqm?(D%_lk*`HVBbu3@W3r^0*Wb?d6?kSOysMgeciP!REU(pt_JLv5 zk#o_yDsU;&;oI+RUyILEQyId4#{g5<7p9$DS@45<&_DfkZLZth+vY=UgzR)LLlq2D zB==@S?qqL>wpk^dd%MX_T*La7)iJ-?j<4FWOPf+cvo7>YRS^M zGLykpTFaQ?yX_qV=&x@wqf0D-elB>@*sAMpsd(NgMqoG-gkARSRm_$s6(&0p-0f&B zh69d78}kEoM?U044<93W+6D@&5?}zy*NNS9gd-EQdMBj=*=i42oPp~AfKnQAXzpW= zp`8RXOj+B(dk07+C{Ou5fm{lx*OVy`+ggoHyHV68*x7uq-NmYATL z2r0&+U`W4P8yLg{Ey?@>CK6vx+bSk|U_=nWbL}-vV|0r<9n9Elj0z%W+>!SDpO~Oo zS$cq5ADC!?Ke&n!M^2#_DeVq&fP6trP?FUGp30*S;O$e*07TFNZX39OrUFrVsLrz! zIhO$0x!n}P1U)Il{JlBc&IAGXOk?2ek#7=;X$b?O7rwqvI7=_q)z+h4qX~}D9GCLC z@*BNWrrdQmYAu~*wyhos>;ClI%_N)BKkT8V(mFJmpbk{DuFRqjJ}bnKcG96=&T(S9 z)m&iHGYXpb{;+mR<`LsIq-L8v2}<3LEHu9%mk~JMyq!)khtbLIQ-78tb+mtelFNVb;`XZ- zJ{bpLWHb6JhEVMfB(Fz{GOrj+~s^eHReL<6CSzHjZz;49ZwK7++! zWn&BES-oc7CC3BBJkrV ztc2Sovnn;)sZtDjy>{KE6B8%FLlGu?Y|>kZbE2L!N?m$Bw6Ib6$kp1~#lBps_LjF# zyym#%Jl_;IfiFV$%pbb5f8Ryt&B8DP& zkDZ>b62X3!k~ES)W3NLi00#4t(am6|6ch86Bq)bC^HV>E`wCVwtTxbOI}RsbI}WjB z`K`^co!Au-=`odU3v()(SV8mdTk{>hKTG>XYNW|0d}r`5CLB3ibUc&(w45N_p7Fd8 zVNozMW#TFSPV-|&H0weUmodosmE35P{=BJNo2J5Sd6|b=gF%XGgh|ZQr1gcbj@GUk zLKMP(J8f74q#4nbN(L0^t@HP*V4m)881mN+Ui{_m7+=bQH@p=q7QNqju_uJXIsx}` ze2IZ1-n@*!-On3zBtrk{*zPj8tf;z^YkZze5NAq9Z|V1Gydmr0!V?w1~2ALUM`EBiJjl)wQ%#;^pkl#iEqY-#b@x4QCTr4dV9 zL=r-u(%9%0SR)tyTE?_YO5~}o7yiomI8TkbBE@E~!EYx;SCmSHfY&$d207x#o}cqn&F<7cvzTOan(?qMj=kDNtuCo!n^s))i- zyv;uOT}d-a0Bc>u}4c zN_u?2tKJr;`s8KB>8+pG)AJbH79K{QBM%egb`bDTo0U-hx#yd_Ck*dZU%z`aq=pY~ zMD=NIa01NXYnsycnAOroylJ1DUx;-BPB*o7#f#S40Nu18Ha?)#Dz%H53vz1v2<}X^ zq&`2r$F{d1=ZOQ(7?hqPdA*9UaC32k&PmWHye=^xhRhv$7l#I(h2&uMP;lS zA|dl8`}~NvOLKE|Lt}k&x`TnD`Q%gAomP3HgJTE;V!RfAtdt@BEO`8ff`L(qEuZF= z7R-Cj#4b1a0x4*%MENqpfyLp9h1qS=y)o)k!QMfd1|}rg#0ycdrC9w9_smv@oL6YP zIPtLcd}l|d$@4hD$}=G2AMCF<(WmKI3^h16C9c>r*s)Ed>Pzr9rM(OO&0O|czkhk{ zo~gPL`5a{#RF>v2CQB0Dz!t968mg<$@+Ym`V@yq^LW)!mR)EL{M6{&p1q_u12=RH` zb~pLfRWJP7Kr>8;`xaPD)W*oV-li&LhoOo3j1%(jWL5n&19Osi!`JpQT8Z@to|`Rftyr%7XIGy_Oo1P8b-bFBNh4 zgjK)OIJ+Q3WTy%JNhDF*-o8K*M1fF$yG(8k72!xUM~0gcU8G44>9R3!o6?EU8X#EO zj0?~Uuqo=Pv0Dc(Q|ET<054v0A5|U@qK@nuqh|FtB;GA4QY?Zr%P>JYd|w!RG=HLc zH=6HP2?gvJX;<}{Ry1fapTWK%9rwcpt0Db(ZZ3m%2>8`_#DpgDU75D}7n&R;s$_Ca z)O3bk)(p+<2`PB>qa(WP_Sark`OlBPpE=y^27+gRTr-3mPm)O!+>kF*;lw?|gyXIe zCOU%S`k0_l(E;F+xo}n@xJ?YhzV09}fT;*j;-B?U7X=c6=h@IIqvJ|h6-KSP?q>+s z&rrD<1}*%ThHPou&_+WF8#puL1=XVAz_*4Gng9@Y&fqCAzTu(YDislfW$8bXr+|vyIu7cvJ2uGV$^Xb=?@dM@dQwxzhbuZ zICMM$U`1NBkpx%9&^igqI0<|^(+~%c!ej_p9UvVf+9WIcsW<7{a%KJM{u+7aGaWaf zE=&-}cP!2*z*A3{!S!pQ8QO+F;;$oRQlHU}br?nT6>7`h@8P=De@+_7t;Q)%cFOkv zQ)KZQ3&cn}dWJtl$b%s`pnb1ojpxN-+;X+M(8~KBxx!faFR7Oczrk3q^{mOQffF2$ zG^tZ>(KMTgkx@fd)hS~kA&pOuj#ZYu?0x%2S^37%#}QJ^aKo>F1X8MAYFi<)ly)EC zh^$hpxnb(4WyKmpBo zSC>cHrwNSz5bY|Tn__}EJkoRpL?z#7O~5O!jX1?$@0@JEX#8$wH#VVhC)TDKF@~yq zKrd`LJxS39h)e$0UPbza+}Q7Qw3bw&+Vfqh^<_7$M*rmxISee9iH-1n?gF}hTqRHL zsjRi_MSWVPV8i)F(I98M*X=$|hXENXS+?!`M_osKU6nXI5 zEmgjVY*vz>MPqCJnjh{?uZFp<>Lv39UWh0eNs$$fufm^3^y;3htg4ST**sxd;4qbQ zgjkm{sm?oBBIIzGdFaJXN-a=hT0jR8a0n&tJzb@ZEa zfY&ov3s!9Q#qo7%kh{bsda)vJVxeAP87dz)Fky3@{ zFeXTV0X4H%}Cjt?7JkFmv(V7~)&nZPWG_Bl10ub`uoMJlm0TCCDBBU^jY9D(X;o zz9oiY`cKY0jyO(xGz7OIY{v)~<~?xi_8&9P`yTSqqH^(9&5P2M^MOuhl54A9;;YkW zCl?r^k@G3&SR_FgK*?@B!(WCOo%A?z(?*gZ9<#~6w|gb7xnb8{IVsE5Dnu12o#Xk@ zBB3I7b-x)^f~H8+{#Ox2_W+a(^T`(gv@Qq9ia3r z#OQnjgJU+(H9@mZlKt>Mx;wf1&bab0rzZ5}40?G9+9%fRbGL|WIff^1A6y0a3Gx$qHZ73!%aT;n zOuW}sOq`z`B0Y{VYZ&)_+~^rN-HSfo6y$Oj)Z<_ldezYufyEH-1Zm5WxUk(wA^0P0 zr!w2=(zORuK}mY&+dh>fn=4@zIoQ2N7mp`tlu3Xo=gnWYTyn1gN)`bm+nuR4+bX0- zx!sJ|rs-1cjk;gl$9*sN)H!AQIY?6V82v3*0SgLUmk=JO$&qwD(*um9@27Ujd{4Jk zDA8+QHmWcPJiaCUQmzjw^37Yl$pN=Eto$NCu+%lX;aLfy-@+k)szozwrZf^Et%%Db zrDNlFN2~s<)W->X1br&5i0{3fD$!x{bx@Y}FY%&ywc-&ln=15#d-WsSL82xQEVxxB)&+j3MaQy?Jlm zjV9|jh4dBv(*MmV!CCdylL`dWj;j zGPqRW7J0>nZl!8p3g1mU?%K7}jz-c+MLpDA7E=bi_G9 zy~o;owM?!WZS@*x*cZ^h1(ZfXGiLw;MbBzFZcshFFy?j13{EgHmD&#Bp;;`H-ei9b zH}nyze)Zldw7G>o#OIo1;7E0|ucZmuF-)z^sXUVavnaQo1vV@vl9S!?-BVwz9tM0e zIo4cSaWwwI$P=skFF>q$LFSt_RBfQ-Y)X@ZvLT^B&{NO+1J#`&D^(+lXLdGrPnK;p zHu@KKs@qN%yMgP0<>S@XBnK|f6zo?4ZXf~hCvSjd>iGtwDNlZ3m&8M(9JHtx8CXZ+ zZxokJD-wwC#H6Q(p7`3(m<`Oj8m&>gd$qP~i!L`&oL}`JFJKbEdFHRwg&ReIY4cND zv77zfWqrAW*_#z48w1bL*lTt&78k+-i}Vn&eVkaAj6Xx@4I zY-BcKJM+`V3iL+y)vpIvxO}HlO_qnsN7dolbG2Rwa~hT(m}xm&vTk4x#X);A@HTba z;%9~zjYxD#;Y`9kCu?i2&_4(*fLRddZUB&uOJNRky6x*V)u^2M`Z$B5fsn~OH;Xmx zPB{3E%^J1~2nG#q-AdsINupV?Y@%1O-N&InhRvl*M^${ofA-jLP5kV?lI^*OeFY(! z0CTs%oYq!dKvNzfr;roF+W5zeRw^W`LH14%%H0ctg!un0Y-enJU7plJ0}Bw1nVHBS z7nx4IEZu+3*wkgL+yKaHTVf}r>^cTzghnjTGD2 zJfjn>GBEt7?(|Zv|Ffs`_c5mP%x@F z^0Do8wqQc}z&MaMwqAp)hZ0beCtEG>Z38Ajt6oj@o$jWWUZmFgA_Mna=+E3N8j|8O^pU88N)j5td%2Uy4WBVc7689( zRucXVuFzy1v`Mm25Q1lD4Asf9enc0blsUH37Y{0`GSx#1y}LHtST+90u`|wKnIJ2G zS64tWHVX6dIPRsc)6x!vRD&xr)|nu78a59o-eY#$5CElI3!%$JG}$mXc9|gQ;%*FC zG=>Sfr4X{*OqFUaM*K|0vwG1?$kGvG+F5+BFmd zNIMyJ5c;H*`M&SBTFXf~j=`cdd#@l=)T??eVW?Mb4ibhZ-nK)AV+5O&=Bel?$W-F9 zG!g(h+_G4I?q*!AH(-LQYNju&li+a{$ORMQv6; z`TW4|RCQdb(C(-9NQ0PcpH$ZGtkJ!h{!6N!U5;VHw6q1h>810QSH}APQL<%#5J68m zs8hlTsE7uQQEjWT2^iAc{nYuo5!nYRS@B0=v(0tb$1oZ|$o!to-xLZZti(LkQ%pHu za_DDPccFq!;4GGU`?n!AqG5&|@Y{;z^V}iZ?;t{ZO8k?Zt+mxv>XSukJ3%&&V8z zuPwbKfbW`15TSt+2-(GX&Dij>)$wDqBCZ>f@saf?uk&bz^iSHXMeb>r`@Q~VhHw|oKmVvG8RwLwCVu0X zU)V(0Ks2q3Ug14Q{|fQ$8qiicJ94YmT9eD%Bd}O=?)Hz^SgEUTg5ht+TO5(CQhQ#q zcQNK%@W&0q{vl1pcG!Zt_ucd!(Q7Hrhnp7I+lQ=VEBb4i2vr%M6@<*)Xs74Sd9QL_bI1%7SQ|P`VS=j4ighyPoUspL#0)(+`j*(;qpweV+8|K>Q8{o zm5>e`D|utn`|adykGgB=naY5JBFMH-%DfqvaY^8t$al4_Vm>tI**U{4R`g$9s$Q|ge z;WB1Z0f=yr3ILZT-(-RYygc{(=GhwO=t_q1?OnAEIyEUJCiLu@!|6nMVedJV>~oY{ z63aoz_;1YrBz+qMA`Wz7yA4@wmQ}z6d3lJYCX}qcTXiaY_^V#(_>ITJ+Mhq(D;tc> z!6)YPmD0G)GHu)&(Q-;@=Id^LRmHvTQ~GYp31=yE0Q3)2R7+ttb|khpyKvp+>YCKu z%~SjOe~DHmu0~6;9zL|=uMjB&AYK}SV-T{L-8djHuV=2uY;(sc>|Ib;e!A+WY$D3o zh6Fq^@?}3-sN-iZh$0%B3z<4+Xk$bdLyw8cdEg%9Ux|OKN6xCJd9I@;6UeuTZX30q zXQp8AX%E}3FSVP8ePq1m<7WQrr*9oi5)9rk7b+FI=j-)nGzmzI=R&)LpsIqYMYBv$ zAPw9^TcKAh+RHMyZg>X4+Ga-s?78NCNw&QkRoGVxWgDXvlTW_TXl0i=*Ybe=9rC#E zBsq6fUR%$rtcL&<#9ddgUElaRFZS`qdFxx#xynf|S{np7w4F|p?dV}NJtFJ;eTU1V zEtl}HxcQ0@mi%rH%ZrkaFUJoVt$2L5=KAvDzF%x~e*!V(;;Jh!H-ynprEk%uROyJ# z%oh@twsaRcvCRZk+N>#Uo}8zf{D2&Rht4aU*&J1wIkmPt`J=z*)YWR>hq9=)76cO% z8I0_*Lbj~{v75?pLQX*@P!qEUJ2b!{A{VA0T!-8Dhc;E4mAB0>uN6zY2_Zpq?_HeZ zJ``V+cq<@xUU={HU7RtbM`=Lm`SbPAG-zuNqhN8Hc9NB#^ah~{+waamCseIF3a#Pb z*1I^|+6va#)+Vh#ec^c&$E7fNj$?GA5+vo4K^V{}+XfNRR{8=18xk3jKJNLA9;v}R zAJkfum;6ZEtxhx@Hp{NME&B`l_mEvZqhNpUBl}d2@p+a$|YD~f9P3_AjRT^VBRSn*KYHHm#l2Z7=W+ohXoz3$X#tA=h zk0Ao-Y#;+AWljw3JOr02=dy@&rYH1vyx#ZTUBupTVqLc@QYy15COcGDjM-FrB^26(V3OrQ8@Myia^soskS05{4Y?jTz)A{W3Q!nr>*_r}^`|Hj3UvyrC5>8EeUirDMju@H;Tv-{)u zSLcQmD5-!w4;s&ITkF|aPxKSFBmZu5{?SClA=5q;QyC8aG*zqQ^L_$syd>2V7LtD*uSA#+)%eqI58IT#A$P5bO#vN9Hm7zt zr4r3=mhf`y3mp^@kTD2x3X1xOW-`{~L)7Y;)ePUP+JxL0*lxOzR;zg?MAyj=DwXm| zOMp=SQ<{|QnCl=xB&QR^d9g-={uGsF#r`Wo%_${MHRf*&S{Z_@r0E%-8h|R^qKPL? zLlHH8K<`QsT7euzXg-5TsOUIZ3~Z{3tC@oDXBxJYkA98UdZ&1f!9H&4D|5zJ-WmnBi4JA#A}4LOry*l-EoU zS9j|^05@q;h_fWeBvJv{EkYhK8BG1CxD?~Nczp2_kp-QGc?!nWb|6nG*xe+lhtq;e z*3=tDiRLGNjv_u(~7e_hG)=!w_d8Zc)IIc1Z#O10i<6}!pN7VyLFLp<%{ z(iY8e48NS<_O)q$LAYy^d#~J1h*(%*AVH$1c>?A)S@&blQUPTULir`gh;-ySoQD>#rn%#PEC1-3ilsI5%U zi6$3Mf*4(_QvyWN-|$k1PhK#UtXf4|1%EVKwq6~6X~xUaiuU1Lx(bGcmj?7;l z6Ft9NS%CAjeN#EPS~+8oCVUA4>lV@a#Jk8EJ%;9_r1%gUz_>_)7y2DsA)t_EIHCZB zd=Ds$-13qN7d1YLX@2zS)YOhHH@Gp$Gmnx*HH4`H9d>d4N<5VOkStwOhu$@Yg5Ixt zUIKQn9zNQ_H`ju`6;4HUTV6u+LQ9z-ZlI|b^LZ&Z<1Y<4*UV?}wMp&=vIZR11SN?M zx2kK(#%PO|u5s+Ro6I+h{H5%vS|mM|H`YFacwB!-vcrpD+#NaL0wXGYQkG#h<23Vc zQpQdMEYF1M))(KHPZeDppcg?;uZG3W%>_&2@7m5NMivh`SP=usam1A_`+F9H8-Gy( zFt-j{|BHTsUnnS})ULJDpHghjE^$boxZFX6m4M%&s`uYEaW2T=xmFL^W8k4>t5aqL zo^yR7)qERs?NZpsz2AKLS)>C6XH(4!6`+eDSwdZKSxPej8kc?2oF8U>ml_b6F}7TH;UMFC?vn{&LX@nIF17uMc^D;f90)kJ=EmkSK>PQ3HP zeVJ3z=&L-h$R`1og|M*A3jxUS^~31(G*rPJ!*KAvO}m3Gy-M5gD`PZUVyKkHNz#D1 zj+-|}ueZOT1lg|NPZt?gEFDI;ymivrXLmjyz7OH>{0$(p?@yLxG}sCX>6P7y!b`bn#bTHrA~CLs7)(frgz_RXm7^D zb2YBHG&1sUJ+#dA{l%w8KL3~lHyPfZ*FD7;M+i{T7v2(G`XlF2M_?7tY?sFkNvTQx z2U`mc55FFKR0GM1u!G+7@^Vo7@-Tma^xRM>z&?9HUuX#o&{pmV$7oWd(SqXmQ-lit85A{0G$gwoq`wjfw3iS70uw1VS7H8Ow zBo?chzmt$1+5^at3^tUO-Z@I6xmuv5llOT1iQm7^eCN7S_a0Uzb&K8z=L{)!Cm*gv z!ae6gl`K=94AXARXC2%4J5>X15b)}I75d=9-np{zv`cvNZYZW){ZZ45Dovf5kW+}( zA)&iA`F=Q_)aIFsGaI(hjEuFN*U==OUQjC}etv0uy6&-&l$ce8QNJ8`UTIU6pcDZS z))ptO+eBI>KO)_*@Ki0iQeEA$e-Zqtvt5yF&0TG$p_0}#pJwB-KHVRNSayX7zLON4pUn4ht6oL6ws*81#W zTavmv)9vJSe%KE8t*YX!W#`>1pz+rzdYF!D&poB0bj%cd3|Ra7anTG^_hX#`EL#@>S~`F50KV^p$r>v_19f33_qpv7BTcg zUlh|H+(NjS=o9^2!>4DrU}?sb6KtL)Wp5X-_BcrU`}tKV0U1_4>x*<7hQ_1wJ!v2S2oraB%jMsn4lMP+vKi+SYB( zhHXAca?gG6CC;QN>9Um-t8`K@=#sel{mL=c4cux!Pa!3); zlF;aa`IR5$;59rk5?0yzlt=AwYQsTkShv+rM!_T~N`l-ApO{%I(Xt6c^dYOE;fRxr zUnsu6V}siF=GU9GOmt-srT=8gWfkcy>{xRAkR zJFwB4I$1<-0f!5yI(w`Er`d;B1RgQe!SuOe)PnR67XxJSQP}v z{o@1$(_WJio|>ufd+e)%rN%<0zgKk>$JUkXPmKE;TMMJ!a>W<@-M&~jND{VjziyC_ z?MNX?cRNFX6w%Bc8Bj1#rjn&(8ozQk+xc0$_7&*@f2Y2qNk3kd_;kYdfwsa2l!STh z@k8M#xZJ{~>&||MdJp?M=fV5#8U9?K^O`$aU&Revv}`n#{X zNz;2}&3&}m7zB!nY(Rv$ls$NcxI&V72fPr&aV=Ql-MCtYQIhKW^CMGlq`rNh{`UJm zF)079mo5rTyCP@hA9_*$F-5jpQ@F#NW3@$=NX|Kx_r>FKOiakn9iilw8?BbW%Mn