meadow 2.0.42 → 2.0.44
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -3
- package/docs/architecture.md +10 -99
- package/docs/diagrams/create-waterfall.excalidraw +2016 -0
- package/docs/diagrams/create-waterfall.mmd +19 -0
- package/docs/diagrams/create-waterfall.svg +2 -0
- package/docs/diagrams/crud-behavior-flow.excalidraw +1305 -0
- package/docs/diagrams/crud-behavior-flow.mmd +13 -0
- package/docs/diagrams/crud-behavior-flow.svg +2 -0
- package/docs/diagrams/module-hierarchy.excalidraw +1582 -0
- package/docs/diagrams/module-hierarchy.mmd +15 -0
- package/docs/diagrams/module-hierarchy.svg +2 -0
- package/docs/diagrams/query-lifecycle.excalidraw +1808 -0
- package/docs/diagrams/query-lifecycle.mmd +21 -0
- package/docs/diagrams/query-lifecycle.svg +2 -0
- package/docs/diagrams/schema-system.excalidraw +2034 -0
- package/docs/diagrams/schema-system.mmd +21 -0
- package/docs/diagrams/schema-system.svg +2 -0
- package/docs/providers/README.md +6 -14
- package/docs/providers/diagrams/overview.excalidraw +1324 -0
- package/docs/providers/diagrams/overview.mmd +8 -0
- package/docs/providers/diagrams/overview.svg +2 -0
- package/docs/providers/diagrams/use-case-unified-client-server-interface.excalidraw +919 -0
- package/docs/providers/diagrams/use-case-unified-client-server-interface.mmd +12 -0
- package/docs/providers/diagrams/use-case-unified-client-server-interface.svg +2 -0
- package/docs/providers/meadow-endpoints.md +5 -17
- package/docs/providers/mongodb.md +2 -2
- package/docs/providers/mssql.md +1 -1
- package/docs/providers/mysql.md +1 -1
- package/docs/providers/postgresql.md +2 -2
- package/docs/providers/rocksdb.md +1 -1
- package/docs/providers/sqlite.md +1 -1
- package/docs/query/README.md +1 -1
- package/docs/query/count.md +2 -8
- package/docs/query/create.md +2 -12
- package/docs/query/diagrams/how-it-works-2.excalidraw +1097 -0
- package/docs/query/diagrams/how-it-works-2.mmd +10 -0
- package/docs/query/diagrams/how-it-works-2.svg +2 -0
- package/docs/query/diagrams/how-it-works-3.excalidraw +665 -0
- package/docs/query/diagrams/how-it-works-3.mmd +6 -0
- package/docs/query/diagrams/how-it-works-3.svg +2 -0
- package/docs/query/diagrams/how-it-works-4.excalidraw +881 -0
- package/docs/query/diagrams/how-it-works-4.mmd +8 -0
- package/docs/query/diagrams/how-it-works-4.svg +2 -0
- package/docs/query/diagrams/how-it-works-5.excalidraw +881 -0
- package/docs/query/diagrams/how-it-works-5.mmd +8 -0
- package/docs/query/diagrams/how-it-works-5.svg +2 -0
- package/docs/query/diagrams/how-it-works.excalidraw +665 -0
- package/docs/query/diagrams/how-it-works.mmd +6 -0
- package/docs/query/diagrams/how-it-works.svg +2 -0
- package/docs/query/read.md +4 -18
- package/docs/query/update.md +2 -10
- package/docs/query-dsl.md +1 -1
- package/docs/quick-start.md +1 -1
- package/docs/retold-catalog.json +1 -1
- package/docs/retold-keyword-index.json +1 -1
- package/docs/schema/README.md +2 -7
- package/docs/schema/diagrams/overview.excalidraw +834 -0
- package/docs/schema/diagrams/overview.mmd +5 -0
- package/docs/schema/diagrams/overview.svg +2 -0
- package/package.json +13 -6
- package/scripts/bookstore-seed.js +136 -1
- package/scripts/meadow-test-cleanup.sh +1 -0
- package/scripts/oracle-test-db.sh +128 -0
- package/source/providers/Meadow-Provider-MeadowEndpoints.js +36 -7
- package/source/providers/Meadow-Provider-Oracle.js +5 -1
- package/test/Meadow-Provider-MeadowEndpoints-Session_tests.js +123 -0
- package/test/Meadow-Provider-Oracle_tests.js +877 -0
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
Schema Definition
|
|
2
|
+
├── Column Schema (array) -> Defines columns, types, and sizes
|
|
3
|
+
├── JSON Schema (object) -> Validates objects against JSON Schema v4
|
|
4
|
+
├── Default Object (object) -> Template merged with new records on create
|
|
5
|
+
└── Authorizer (object) -> Role-based access control per operation
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 792 188" width="792" height="188"><!-- svg-source:excalidraw --><metadata><!-- payload-type:application/vnd.excalidraw+json --><!-- payload-version:2 --><!-- payload-start -->eyJ2ZXJzaW9uIjoiMSIsImVuY29kaW5nIjoiYnN0cmluZyIsImNvbXByZXNzZWQiOnRydWUsImVuY29kZWQiOiJ4nO1cXFtzmzhcdTAwMTR+z69gvC+7M3GKLkiQh53JzdvLtt1pOrtcdTAwMGY7fVBAsdlgYEBOmnb631fCjoVcdTAwMDFcdTAwMTewaUpakpkk6MbR0fehcz7kfD4wjJG4j/no2Fx1MDAxOPGPLlx1MDAwYnwvYXejQ1V+y5PUj0JZXHUwMDA1s+s0WiRu1nImRHz87Fx1MDAxOYD0yJTf4NiiXHUwMDE4gGUvXHUwMDFl8DlcdTAwMGZFKtv9K69ccuNz9lPW+J7qey3GYeTxsVx1MDAwNVDWIatam1x1MDAxMFx1MDAwNH6ccl3xUd1cdTAwMWSvL+/lJTLXl3e+J2ayyF6XzLg/nYmNXCJcdTAwMTZOXHUwMDAzNbjulookuuFnUVx1MDAxMCXqpr+cOcSEXHUwMDEzfdMr5t5Mk2hcdTAwMTF629tcXPtBcCnus5GlZ6TfRoXx/1lcdTAwMTlcdTAwMDeOcKFmWz95y+ks5Gm6YW1cdTAwMTQz11x1MDAxN2rmwNSlyr74hZe5+YO2KmFz/kL5OVxcXHUwMDA0QX7g0FtccrxRkXKuXHUwMDFhy7VYXHUwMDE3XHUwMDE1Vj1f9iZcbrP1XHUwMDA30CZcdTAwMTRAZOpcdTAwMTZ+ei5cdTAwMTdeZKNdsyDl2pnq3lx1MDAxNzlQaGtcdTAwMTexx5ZdXHUwMDAwtU1sOSagZm6OgVx1MDAxZt5cdTAwMTQtXHUwMDBlXCL3puIufuhxhZVcdTAwMTEzR1nZl8Nt4JNcdTAwMWVcdTAwMWGbZehcdP5RbOJcdTAwMGXTXHLcQVDCXHUwMDFkNElcdTAwMTl5sGPoiYSFacxcdTAwMTLpv53gt1x1MDAwM/jAY4JcdTAwMGZcdTAwMDPcXG58iFBMILJJb8CXQUd69NKd8Tkzzvm1XHUwMDFm+kLNQ/smXG7Fpf+JZ6DZKJ2wuVx1MDAxZihcdTAwMDdbXHUwMDFi451cdTAwMDT+VPlhXHUwMDE08OvcuktnXGJfPqbX1VwiinWtK8djfsiT8ipEiT/1Q1x1MDAxNryvt5UtRPSOp0trRbLgeZ/w51x1MDAwZjhcdTAwMDdHUJus+Vx1MDAwN2r4x4Or8e1cdTAwMTiUXHSoXHUwMDA2Lzz4NZMyXHUwMDA3lVx0qF25plx1MDAxZtJG1dPPPqFcdTAwMTNcbvek34y5s0XCtz//UaGm0fP/SM/jXHUwMDExSOiQXHUwMDEy4b5KQotcdTAwMDJcdTAwMDdcdTAwMTMzt1x1MDAxN39vXHUwMDEyalx1MDAwNObWM478fCiivvRfhlx1MDAwNkZ2sf77w2F9a2Tp5lx1MDAwN4Vuo4Cl4iyaz30hJ/eXsqHkdsFcdTAwMTJxKm32w2mxjofelpqs10mSRHczzkprLPttrYuj4H6arWnmtXqKznaiKHFKXHUwMDE0XHUwMDA1XHUwMDE1W6Re4IGiLSjaKkiDwLFcdTAwMWOLOHqB+sNQ9I1cdTAwMTiqsVZo/qMxNMuggGnBhimUtZlCXHUwMDExXHLcjlKoXHUwMDA2LC21+aFSKLVcdTAwMTitdlCIiVx1MDAwNUgvN1DcJIWq2Fx1MDAxZcopXHUwMDE03UyhLFLCXHUwMDFkzLltt1x1MDAxNFxunIJcdEQ/dVxu5Vjt8ndHhm9cYlx1MDAxMbs/+ftDXG4ll2wxXHUwMDBmjVV28itLXHUwMDEydv9bj9OoXHUwMDFhe/dLpaxcdTAwMWFcdTAwMWW6c9GMhohqZ2U+KodpXGJrXGJpXHUwMDFlaoA8UqD21HnYSsogjoOgNKZ/Ssb496UywFPDzVx1MDAxMJ5cdTAwMWVcdTAwMWFcbl7yXHUwMDE3XHUwMDBiPUNcdTAwMDE6rWRlLtr/jqxsZ/5+JCWN9I6KQK02mbLLu+Wgd3TEVFx1MDAwMuw87GqZXG5tXHUwMDFiUJpTKr83UzVcdTAwMDDpIHd0IXfswlBgakBcZnpH51x1MDAxNNVRSpOgXHUwMDE2QMtxXHUwMDAwIf1cdGo1R+1B8OhA8KCmXSZpXHUwMDEzvSOP0UHw6IaecjHa0Fx1MDAxM5rUsYlcdTAwMDNoXHUwMDFmXHUwMDA1XHUwMDBmp4ngUbFB1FxuXHUwMDFlTsU7Y1xcXHUwMDExxFxygkfLvcFstTcgi1x1MDAxMEox7M/W8JBovbx8+2atXHUwMDFlRFf/cVf0We74urn7JVInXHLUjkZcdTAwMWMsqlx1MDAxZE45SMNmxeN/UDvaXHUwMDA2aGZcdTAwMWVhdSSkjoNcdTAwMTFAuJdqx9/q5JtcdTAwMWM3NZaoTlxyNpWcSIWRh/wt7rfo0X5cdTAwMTb7Ufa0kfZRcc6vPrOqOG01iFx1MDAxZlx1MDAxZFx1MDAxMVx1MDAxN1x1MDAxMZKHX/2rKkBsXHUwMDA0bKuP6sfZoH50oX7sxFE0nPb4hlx1MDAxY9WZRFx1MDAxM47a6m2ySrF6yNHzQf3oQP3AXHUwMDE22VH9QMNxj67pia1WWyikwDFcdTAwMWS7R2/6NDsvmohcdTAwMWZcdTAwMTX7Q634XHUwMDAxYMVxXHUwMDBmapWRN6hcdTAwMWYt91x1MDAwNqvV3lx1MDAwME3bXCJcdTAwMTTiXHUwMDFlXHUwMDFkXHUwMDA1fMi8zvk1W1x1MDAwNMJ4m6UrT0FcdTAwMDGptXi/jGrSQFx1MDAwNGnExaJcYlx1MDAwMmA5WMOw6uMrg1xu0pKMrXRwgFx1MDAwMJFUNHukg+dkkPd8XHUwMDFlXHUwMDA3clxcY86TKfeMO1/MjJDfXHUwMDE5XHR3o8RLjSg03ITLXHUwMDE2/Vx1MDAxNkJ2mcd+xP2jkVx1MDAxNILL1K1PsypOTVZIIaDj+O3nSLMgbffhM2hSgm2I+/MmQUPw+WNIIcDWzVx1MDAwZlxu3Z56mrWUQnbiKFx1MDAxZFx1MDAwZYJ8Q47q2zXgqIMxIZj06GWfpuiLQVx06UBcdEGkgqONlJBcXNQ1KCFdXHSVrXZQiGxgXHUwMDEzp5efe3nZRFx0qYBevVx1MDAxMkIqzoHkXHUwMDEyskFcdNl1ayCttlx1MDAwNmhigJBcdHukkj8kXydcdTAwMGIxk4nMJ548XHUwMDA1XHUwMDE15KvW7pdIvWqggDTiYElcdTAwMDEh5Vx1MDAxOFxyOcM5kFx1MDAwZUjY7nWyXHUwMDAzsIVMQvvzOjmngLyLXHUwMDAyPr5iKfdcZua6ctKGokVcdTAwMTJcdTAwMDVGLMFcdTAwMWXJXHUwMDFmbOt/9uiN/NF6XHUwMDEy+1H2z1x1MDAxNWVcdTAwMGZWgeaIxfGlUOLK8YrAXHUwMDEycL5XeIIty1x1MDAwNI+1h7Ki1zLEu1xi2VVQXFyo0a3P704r4qvJ6YReXFysZrNa49eLQPiXXHUwMDEyVa6aqYLOZ2Vf9lhR5OOroi//XHUwMDAzo93UWSJ9<!-- payload-end --><pict-renderer-graph:source xmlns:pict-renderer-graph="https://fable-retold.github.io/pict-renderer-graph/ns/v1"><![CDATA[{"type":"filetree","mermaid":"Schema Definition\n ├── Column Schema (array) -> Defines columns, types, and sizes\n ├── JSON Schema (object) -> Validates objects against JSON Schema v4\n ├── Default Object (object) -> Template merged with new records on create\n └── Authorizer (object) -> Role-based access control per operation\n","style":"notebook"}]]></pict-renderer-graph:source></metadata><defs><style class="style-fonts">
|
|
2
|
+
@font-face { font-family: Excalifont; src: url(data:font/woff2;base64,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); }</style></defs><g stroke-linecap="round" transform="translate(10 19) rotate(0 4 4)"><path d="M8 4 C8 4.23, 7.98 4.47, 7.94 4.69 C7.9 4.92, 7.84 5.15, 7.76 5.37 C7.68 5.59, 7.58 5.8, 7.46 6 C7.35 6.2, 7.21 6.39, 7.06 6.57 C6.92 6.75, 6.75 6.92, 6.57 7.06 C6.39 7.21, 6.2 7.35, 6 7.46 C5.8 7.58, 5.59 7.68, 5.37 7.76 C5.15 7.84, 4.92 7.9, 4.69 7.94 C4.47 7.98, 4.23 8, 4 8 C3.77 8, 3.53 7.98, 3.31 7.94 C3.08 7.9, 2.85 7.84, 2.63 7.76 C2.41 7.68, 2.2 7.58, 2 7.46 C1.8 7.35, 1.61 7.21, 1.43 7.06 C1.25 6.92, 1.08 6.75, 0.94 6.57 C0.79 6.39, 0.65 6.2, 0.54 6 C0.42 5.8, 0.32 5.59, 0.24 5.37 C0.16 5.15, 0.1 4.92, 0.06 4.69 C0.02 4.47, 0 4.23, 0 4 C0 3.77, 0.02 3.53, 0.06 3.31 C0.1 3.08, 0.16 2.85, 0.24 2.63 C0.32 2.41, 0.42 2.2, 0.54 2 C0.65 1.8, 0.79 1.61, 0.94 1.43 C1.08 1.25, 1.25 1.08, 1.43 0.94 C1.61 0.79, 1.8 0.65, 2 0.54 C2.2 0.42, 2.41 0.32, 2.63 0.24 C2.85 0.16, 3.08 0.1, 3.31 0.06 C3.53 0.02, 3.77 0, 4 0 C4.23 0, 4.47 0.02, 4.69 0.06 C4.92 0.1, 5.15 0.16, 5.37 0.24 C5.59 0.32, 5.8 0.42, 6 0.54 C6.2 0.65, 6.39 0.79, 6.57 0.94 C6.75 1.08, 6.92 1.25, 7.06 1.43 C7.21 1.61, 7.35 1.8, 7.46 2 C7.58 2.2, 7.68 2.41, 7.76 2.63 C7.84 2.85, 7.9 3.08, 7.94 3.31 C7.98 3.53, 7.99 3.88, 8 4 C8.01 4.12, 8.01 3.88, 8 4" stroke="none" stroke-width="0" fill="var(--diagram-accent, #C9602F)"/><path d="M8 4 C8 4.23, 7.98 4.47, 7.94 4.69 C7.9 4.92, 7.84 5.15, 7.76 5.37 C7.68 5.59, 7.58 5.8, 7.46 6 C7.35 6.2, 7.21 6.39, 7.06 6.57 C6.92 6.75, 6.75 6.92, 6.57 7.06 C6.39 7.21, 6.2 7.35, 6 7.46 C5.8 7.58, 5.59 7.68, 5.37 7.76 C5.15 7.84, 4.92 7.9, 4.69 7.94 C4.47 7.98, 4.23 8, 4 8 C3.77 8, 3.53 7.98, 3.31 7.94 C3.08 7.9, 2.85 7.84, 2.63 7.76 C2.41 7.68, 2.2 7.58, 2 7.46 C1.8 7.35, 1.61 7.21, 1.43 7.06 C1.25 6.92, 1.08 6.75, 0.94 6.57 C0.79 6.39, 0.65 6.2, 0.54 6 C0.42 5.8, 0.32 5.59, 0.24 5.37 C0.16 5.15, 0.1 4.92, 0.06 4.69 C0.02 4.47, 0 4.23, 0 4 C0 3.77, 0.02 3.53, 0.06 3.31 C0.1 3.08, 0.16 2.85, 0.24 2.63 C0.32 2.41, 0.42 2.2, 0.54 2 C0.65 1.8, 0.79 1.61, 0.94 1.43 C1.08 1.25, 1.25 1.08, 1.43 0.94 C1.61 0.79, 1.8 0.65, 2 0.54 C2.2 0.42, 2.41 0.32, 2.63 0.24 C2.85 0.16, 3.08 0.1, 3.31 0.06 C3.53 0.02, 3.77 0, 4 0 C4.23 0, 4.47 0.02, 4.69 0.06 C4.92 0.1, 5.15 0.16, 5.37 0.24 C5.59 0.32, 5.8 0.42, 6 0.54 C6.2 0.65, 6.39 0.79, 6.57 0.94 C6.75 1.08, 6.92 1.25, 7.06 1.43 C7.21 1.61, 7.35 1.8, 7.46 2 C7.58 2.2, 7.68 2.41, 7.76 2.63 C7.84 2.85, 7.9 3.08, 7.94 3.31 C7.98 3.53, 7.99 3.88, 8 4 C8.01 4.12, 8.01 3.88, 8 4" stroke="var(--diagram-accent, #C9602F)" stroke-width="1.4" fill="none"/></g><g transform="translate(33 10) rotate(0 103 14)"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, sans-serif, Segoe UI Emoji" font-size="20px" fill="var(--diagram-accent, #C9602F)" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">Schema Definition</text></g><g stroke-linecap="round"><g transform="translate(14 40) rotate(0 -0.11730230889380344 17.5)"><path d="M0 0 C-0.28 7.47, -0.35 14.55, 0 35 M0 0 C0 9.13, -0.08 18.14, 0 35" stroke="var(--diagram-deemphasis, #8A7F72)" stroke-width="1.3" fill="none"/></g></g><mask/><g stroke-linecap="round"><g transform="translate(14 58) rotate(0 8 0.02193744430524447)"><path d="M0 0 C3.58 0.08, 6.55 0.06, 16 0 M0 0 C5.46 0.13, 10.59 -0.05, 16 0" stroke="var(--diagram-deemphasis, #8A7F72)" stroke-width="1.3" fill="none"/></g></g><mask/><g stroke-linecap="round" transform="translate(40 54) rotate(0 4 4)"><path d="M8 4 C8 4.23, 7.98 4.47, 7.94 4.69 C7.9 4.92, 7.84 5.15, 7.76 5.37 C7.68 5.59, 7.58 5.8, 7.46 6 C7.35 6.2, 7.21 6.39, 7.06 6.57 C6.92 6.75, 6.75 6.92, 6.57 7.06 C6.39 7.21, 6.2 7.35, 6 7.46 C5.8 7.58, 5.59 7.68, 5.37 7.76 C5.15 7.84, 4.92 7.9, 4.69 7.94 C4.47 7.98, 4.23 8, 4 8 C3.77 8, 3.53 7.98, 3.31 7.94 C3.08 7.9, 2.85 7.84, 2.63 7.76 C2.41 7.68, 2.2 7.58, 2 7.46 C1.8 7.35, 1.61 7.21, 1.43 7.06 C1.25 6.92, 1.08 6.75, 0.94 6.57 C0.79 6.39, 0.65 6.2, 0.54 6 C0.42 5.8, 0.32 5.59, 0.24 5.37 C0.16 5.15, 0.1 4.92, 0.06 4.69 C0.02 4.47, 0 4.23, 0 4 C0 3.77, 0.02 3.53, 0.06 3.31 C0.1 3.08, 0.16 2.85, 0.24 2.63 C0.32 2.41, 0.42 2.2, 0.54 2 C0.65 1.8, 0.79 1.61, 0.94 1.43 C1.08 1.25, 1.25 1.08, 1.43 0.94 C1.61 0.79, 1.8 0.65, 2 0.54 C2.2 0.42, 2.41 0.32, 2.63 0.24 C2.85 0.16, 3.08 0.1, 3.31 0.06 C3.53 0.02, 3.77 0, 4 0 C4.23 0, 4.47 0.02, 4.69 0.06 C4.92 0.1, 5.15 0.16, 5.37 0.24 C5.59 0.32, 5.8 0.42, 6 0.54 C6.2 0.65, 6.39 0.79, 6.57 0.94 C6.75 1.08, 6.92 1.25, 7.06 1.43 C7.21 1.61, 7.35 1.8, 7.46 2 C7.58 2.2, 7.68 2.41, 7.76 2.63 C7.84 2.85, 7.9 3.08, 7.94 3.31 C7.98 3.53, 7.99 3.88, 8 4 C8.01 4.12, 8.01 3.88, 8 4" stroke="none" stroke-width="0" fill="var(--diagram-deemphasis, #8A7F72)"/><path d="M8 4 C8 4.23, 7.98 4.47, 7.94 4.69 C7.9 4.92, 7.84 5.15, 7.76 5.37 C7.68 5.59, 7.58 5.8, 7.46 6 C7.35 6.2, 7.21 6.39, 7.06 6.57 C6.92 6.75, 6.75 6.92, 6.57 7.06 C6.39 7.21, 6.2 7.35, 6 7.46 C5.8 7.58, 5.59 7.68, 5.37 7.76 C5.15 7.84, 4.92 7.9, 4.69 7.94 C4.47 7.98, 4.23 8, 4 8 C3.77 8, 3.53 7.98, 3.31 7.94 C3.08 7.9, 2.85 7.84, 2.63 7.76 C2.41 7.68, 2.2 7.58, 2 7.46 C1.8 7.35, 1.61 7.21, 1.43 7.06 C1.25 6.92, 1.08 6.75, 0.94 6.57 C0.79 6.39, 0.65 6.2, 0.54 6 C0.42 5.8, 0.32 5.59, 0.24 5.37 C0.16 5.15, 0.1 4.92, 0.06 4.69 C0.02 4.47, 0 4.23, 0 4 C0 3.77, 0.02 3.53, 0.06 3.31 C0.1 3.08, 0.16 2.85, 0.24 2.63 C0.32 2.41, 0.42 2.2, 0.54 2 C0.65 1.8, 0.79 1.61, 0.94 1.43 C1.08 1.25, 1.25 1.08, 1.43 0.94 C1.61 0.79, 1.8 0.65, 2 0.54 C2.2 0.42, 2.41 0.32, 2.63 0.24 C2.85 0.16, 3.08 0.1, 3.31 0.06 C3.53 0.02, 3.77 0, 4 0 C4.23 0, 4.47 0.02, 4.69 0.06 C4.92 0.1, 5.15 0.16, 5.37 0.24 C5.59 0.32, 5.8 0.42, 6 0.54 C6.2 0.65, 6.39 0.79, 6.57 0.94 C6.75 1.08, 6.92 1.25, 7.06 1.43 C7.21 1.61, 7.35 1.8, 7.46 2 C7.58 2.2, 7.68 2.41, 7.76 2.63 C7.84 2.85, 7.9 3.08, 7.94 3.31 C7.98 3.53, 7.99 3.88, 8 4 C8.01 4.12, 8.01 3.88, 8 4" stroke="var(--diagram-deemphasis, #8A7F72)" stroke-width="1.4" fill="none"/></g><g transform="translate(63 45) rotate(0 126 14)"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, sans-serif, Segoe UI Emoji" font-size="20px" fill="var(--diagram-ink, #1B1F23)" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">Column Schema (array)</text></g><g transform="translate(356 48) rotate(0 171.5 11)"><text x="0" y="14.096" font-family="Excalifont, Xiaolai, sans-serif, Segoe UI Emoji" font-size="16px" fill="var(--diagram-deemphasis, #8A7F72)" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">-> Defines columns, types, and sizes</text></g><g stroke-linecap="round"><g transform="translate(14 75) rotate(0 0.017623624040256303 17.5)"><path d="M0 0 C-0.04 7.52, 0.11 14.4, 0 35 M0 0 C0.09 10.46, 0.01 20.4, 0 35" stroke="var(--diagram-deemphasis, #8A7F72)" stroke-width="1.3" fill="none"/></g></g><mask/><g stroke-linecap="round"><g transform="translate(14 93) rotate(0 8 -0.02947472612343205)"><path d="M0 0 C2.97 0.15, 6.1 0.02, 16 0 M0 0 C5.71 -0.18, 11.79 -0.17, 16 0" stroke="var(--diagram-deemphasis, #8A7F72)" stroke-width="1.3" fill="none"/></g></g><mask/><g stroke-linecap="round" transform="translate(40 89) rotate(0 4 4)"><path d="M8 4 C8 4.23, 7.98 4.47, 7.94 4.69 C7.9 4.92, 7.84 5.15, 7.76 5.37 C7.68 5.59, 7.58 5.8, 7.46 6 C7.35 6.2, 7.21 6.39, 7.06 6.57 C6.92 6.75, 6.75 6.92, 6.57 7.06 C6.39 7.21, 6.2 7.35, 6 7.46 C5.8 7.58, 5.59 7.68, 5.37 7.76 C5.15 7.84, 4.92 7.9, 4.69 7.94 C4.47 7.98, 4.23 8, 4 8 C3.77 8, 3.53 7.98, 3.31 7.94 C3.08 7.9, 2.85 7.84, 2.63 7.76 C2.41 7.68, 2.2 7.58, 2 7.46 C1.8 7.35, 1.61 7.21, 1.43 7.06 C1.25 6.92, 1.08 6.75, 0.94 6.57 C0.79 6.39, 0.65 6.2, 0.54 6 C0.42 5.8, 0.32 5.59, 0.24 5.37 C0.16 5.15, 0.1 4.92, 0.06 4.69 C0.02 4.47, 0 4.23, 0 4 C0 3.77, 0.02 3.53, 0.06 3.31 C0.1 3.08, 0.16 2.85, 0.24 2.63 C0.32 2.41, 0.42 2.2, 0.54 2 C0.65 1.8, 0.79 1.61, 0.94 1.43 C1.08 1.25, 1.25 1.08, 1.43 0.94 C1.61 0.79, 1.8 0.65, 2 0.54 C2.2 0.42, 2.41 0.32, 2.63 0.24 C2.85 0.16, 3.08 0.1, 3.31 0.06 C3.53 0.02, 3.77 0, 4 0 C4.23 0, 4.47 0.02, 4.69 0.06 C4.92 0.1, 5.15 0.16, 5.37 0.24 C5.59 0.32, 5.8 0.42, 6 0.54 C6.2 0.65, 6.39 0.79, 6.57 0.94 C6.75 1.08, 6.92 1.25, 7.06 1.43 C7.21 1.61, 7.35 1.8, 7.46 2 C7.58 2.2, 7.68 2.41, 7.76 2.63 C7.84 2.85, 7.9 3.08, 7.94 3.31 C7.98 3.53, 7.99 3.88, 8 4 C8.01 4.12, 8.01 3.88, 8 4" stroke="none" stroke-width="0" fill="var(--diagram-deemphasis, #8A7F72)"/><path d="M8 4 C8 4.23, 7.98 4.47, 7.94 4.69 C7.9 4.92, 7.84 5.15, 7.76 5.37 C7.68 5.59, 7.58 5.8, 7.46 6 C7.35 6.2, 7.21 6.39, 7.06 6.57 C6.92 6.75, 6.75 6.92, 6.57 7.06 C6.39 7.21, 6.2 7.35, 6 7.46 C5.8 7.58, 5.59 7.68, 5.37 7.76 C5.15 7.84, 4.92 7.9, 4.69 7.94 C4.47 7.98, 4.23 8, 4 8 C3.77 8, 3.53 7.98, 3.31 7.94 C3.08 7.9, 2.85 7.84, 2.63 7.76 C2.41 7.68, 2.2 7.58, 2 7.46 C1.8 7.35, 1.61 7.21, 1.43 7.06 C1.25 6.92, 1.08 6.75, 0.94 6.57 C0.79 6.39, 0.65 6.2, 0.54 6 C0.42 5.8, 0.32 5.59, 0.24 5.37 C0.16 5.15, 0.1 4.92, 0.06 4.69 C0.02 4.47, 0 4.23, 0 4 C0 3.77, 0.02 3.53, 0.06 3.31 C0.1 3.08, 0.16 2.85, 0.24 2.63 C0.32 2.41, 0.42 2.2, 0.54 2 C0.65 1.8, 0.79 1.61, 0.94 1.43 C1.08 1.25, 1.25 1.08, 1.43 0.94 C1.61 0.79, 1.8 0.65, 2 0.54 C2.2 0.42, 2.41 0.32, 2.63 0.24 C2.85 0.16, 3.08 0.1, 3.31 0.06 C3.53 0.02, 3.77 0, 4 0 C4.23 0, 4.47 0.02, 4.69 0.06 C4.92 0.1, 5.15 0.16, 5.37 0.24 C5.59 0.32, 5.8 0.42, 6 0.54 C6.2 0.65, 6.39 0.79, 6.57 0.94 C6.75 1.08, 6.92 1.25, 7.06 1.43 C7.21 1.61, 7.35 1.8, 7.46 2 C7.58 2.2, 7.68 2.41, 7.76 2.63 C7.84 2.85, 7.9 3.08, 7.94 3.31 C7.98 3.53, 7.99 3.88, 8 4 C8.01 4.12, 8.01 3.88, 8 4" stroke="var(--diagram-deemphasis, #8A7F72)" stroke-width="1.4" fill="none"/></g><g transform="translate(63 80) rotate(0 120 14)"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, sans-serif, Segoe UI Emoji" font-size="20px" fill="var(--diagram-ink, #1B1F23)" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">JSON Schema (object)</text></g><g transform="translate(356 83) rotate(0 204 11)"><text x="0" y="14.096" font-family="Excalifont, Xiaolai, sans-serif, Segoe UI Emoji" font-size="16px" fill="var(--diagram-deemphasis, #8A7F72)" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">-> Validates objects against JSON Schema v4</text></g><g stroke-linecap="round"><g transform="translate(14 110) rotate(0 0.02587434698974711 17.5)"><path d="M0 0 C-0.13 6.75, 0.18 14.05, 0 35 M0 0 C0.23 12.03, -0.1 24.23, 0 35" stroke="var(--diagram-deemphasis, #8A7F72)" stroke-width="1.3" fill="none"/></g></g><mask/><g stroke-linecap="round"><g transform="translate(14 128) rotate(0 8 0.02390454490115701)"><path d="M0 0 C2.95 0.33, 6.18 -0.24, 16 0 M0 0 C3.55 -0.14, 7.14 0.07, 16 0" stroke="var(--diagram-deemphasis, #8A7F72)" stroke-width="1.3" fill="none"/></g></g><mask/><g stroke-linecap="round" transform="translate(40 124) rotate(0 4 4)"><path d="M8 4 C8 4.23, 7.98 4.47, 7.94 4.69 C7.9 4.92, 7.84 5.15, 7.76 5.37 C7.68 5.59, 7.58 5.8, 7.46 6 C7.35 6.2, 7.21 6.39, 7.06 6.57 C6.92 6.75, 6.75 6.92, 6.57 7.06 C6.39 7.21, 6.2 7.35, 6 7.46 C5.8 7.58, 5.59 7.68, 5.37 7.76 C5.15 7.84, 4.92 7.9, 4.69 7.94 C4.47 7.98, 4.23 8, 4 8 C3.77 8, 3.53 7.98, 3.31 7.94 C3.08 7.9, 2.85 7.84, 2.63 7.76 C2.41 7.68, 2.2 7.58, 2 7.46 C1.8 7.35, 1.61 7.21, 1.43 7.06 C1.25 6.92, 1.08 6.75, 0.94 6.57 C0.79 6.39, 0.65 6.2, 0.54 6 C0.42 5.8, 0.32 5.59, 0.24 5.37 C0.16 5.15, 0.1 4.92, 0.06 4.69 C0.02 4.47, 0 4.23, 0 4 C0 3.77, 0.02 3.53, 0.06 3.31 C0.1 3.08, 0.16 2.85, 0.24 2.63 C0.32 2.41, 0.42 2.2, 0.54 2 C0.65 1.8, 0.79 1.61, 0.94 1.43 C1.08 1.25, 1.25 1.08, 1.43 0.94 C1.61 0.79, 1.8 0.65, 2 0.54 C2.2 0.42, 2.41 0.32, 2.63 0.24 C2.85 0.16, 3.08 0.1, 3.31 0.06 C3.53 0.02, 3.77 0, 4 0 C4.23 0, 4.47 0.02, 4.69 0.06 C4.92 0.1, 5.15 0.16, 5.37 0.24 C5.59 0.32, 5.8 0.42, 6 0.54 C6.2 0.65, 6.39 0.79, 6.57 0.94 C6.75 1.08, 6.92 1.25, 7.06 1.43 C7.21 1.61, 7.35 1.8, 7.46 2 C7.58 2.2, 7.68 2.41, 7.76 2.63 C7.84 2.85, 7.9 3.08, 7.94 3.31 C7.98 3.53, 7.99 3.88, 8 4 C8.01 4.12, 8.01 3.88, 8 4" stroke="none" stroke-width="0" fill="var(--diagram-deemphasis, #8A7F72)"/><path d="M8 4 C8 4.23, 7.98 4.47, 7.94 4.69 C7.9 4.92, 7.84 5.15, 7.76 5.37 C7.68 5.59, 7.58 5.8, 7.46 6 C7.35 6.2, 7.21 6.39, 7.06 6.57 C6.92 6.75, 6.75 6.92, 6.57 7.06 C6.39 7.21, 6.2 7.35, 6 7.46 C5.8 7.58, 5.59 7.68, 5.37 7.76 C5.15 7.84, 4.92 7.9, 4.69 7.94 C4.47 7.98, 4.23 8, 4 8 C3.77 8, 3.53 7.98, 3.31 7.94 C3.08 7.9, 2.85 7.84, 2.63 7.76 C2.41 7.68, 2.2 7.58, 2 7.46 C1.8 7.35, 1.61 7.21, 1.43 7.06 C1.25 6.92, 1.08 6.75, 0.94 6.57 C0.79 6.39, 0.65 6.2, 0.54 6 C0.42 5.8, 0.32 5.59, 0.24 5.37 C0.16 5.15, 0.1 4.92, 0.06 4.69 C0.02 4.47, 0 4.23, 0 4 C0 3.77, 0.02 3.53, 0.06 3.31 C0.1 3.08, 0.16 2.85, 0.24 2.63 C0.32 2.41, 0.42 2.2, 0.54 2 C0.65 1.8, 0.79 1.61, 0.94 1.43 C1.08 1.25, 1.25 1.08, 1.43 0.94 C1.61 0.79, 1.8 0.65, 2 0.54 C2.2 0.42, 2.41 0.32, 2.63 0.24 C2.85 0.16, 3.08 0.1, 3.31 0.06 C3.53 0.02, 3.77 0, 4 0 C4.23 0, 4.47 0.02, 4.69 0.06 C4.92 0.1, 5.15 0.16, 5.37 0.24 C5.59 0.32, 5.8 0.42, 6 0.54 C6.2 0.65, 6.39 0.79, 6.57 0.94 C6.75 1.08, 6.92 1.25, 7.06 1.43 C7.21 1.61, 7.35 1.8, 7.46 2 C7.58 2.2, 7.68 2.41, 7.76 2.63 C7.84 2.85, 7.9 3.08, 7.94 3.31 C7.98 3.53, 7.99 3.88, 8 4 C8.01 4.12, 8.01 3.88, 8 4" stroke="var(--diagram-deemphasis, #8A7F72)" stroke-width="1.4" fill="none"/></g><g transform="translate(63 115) rotate(0 137.5 14)"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, sans-serif, Segoe UI Emoji" font-size="20px" fill="var(--diagram-ink, #1B1F23)" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">Default Object (object)</text></g><g transform="translate(356 118) rotate(0 213 11)"><text x="0" y="14.096" font-family="Excalifont, Xiaolai, sans-serif, Segoe UI Emoji" font-size="16px" fill="var(--diagram-deemphasis, #8A7F72)" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">-> Template merged with new records on create</text></g><g stroke-linecap="round"><g transform="translate(14 145) rotate(0 -0.016852893708810157 9)"><path d="M0 0 C0.18 3.2, -0.38 7.4, 0 18 M0 0 C0.17 5.76, 0.1 11.59, 0 18" stroke="var(--diagram-deemphasis, #8A7F72)" stroke-width="1.3" fill="none"/></g></g><mask/><g stroke-linecap="round"><g transform="translate(14 163) rotate(0 8 0.0359022393515005)"><path d="M0 0 C3.17 0.22, 6.45 -0.01, 16 0 M0 0 C6.36 -0.09, 12.59 0.11, 16 0" stroke="var(--diagram-deemphasis, #8A7F72)" stroke-width="1.3" fill="none"/></g></g><mask/><g stroke-linecap="round" transform="translate(40 159) rotate(0 4 4)"><path d="M8 4 C8 4.23, 7.98 4.47, 7.94 4.69 C7.9 4.92, 7.84 5.15, 7.76 5.37 C7.68 5.59, 7.58 5.8, 7.46 6 C7.35 6.2, 7.21 6.39, 7.06 6.57 C6.92 6.75, 6.75 6.92, 6.57 7.06 C6.39 7.21, 6.2 7.35, 6 7.46 C5.8 7.58, 5.59 7.68, 5.37 7.76 C5.15 7.84, 4.92 7.9, 4.69 7.94 C4.47 7.98, 4.23 8, 4 8 C3.77 8, 3.53 7.98, 3.31 7.94 C3.08 7.9, 2.85 7.84, 2.63 7.76 C2.41 7.68, 2.2 7.58, 2 7.46 C1.8 7.35, 1.61 7.21, 1.43 7.06 C1.25 6.92, 1.08 6.75, 0.94 6.57 C0.79 6.39, 0.65 6.2, 0.54 6 C0.42 5.8, 0.32 5.59, 0.24 5.37 C0.16 5.15, 0.1 4.92, 0.06 4.69 C0.02 4.47, 0 4.23, 0 4 C0 3.77, 0.02 3.53, 0.06 3.31 C0.1 3.08, 0.16 2.85, 0.24 2.63 C0.32 2.41, 0.42 2.2, 0.54 2 C0.65 1.8, 0.79 1.61, 0.94 1.43 C1.08 1.25, 1.25 1.08, 1.43 0.94 C1.61 0.79, 1.8 0.65, 2 0.54 C2.2 0.42, 2.41 0.32, 2.63 0.24 C2.85 0.16, 3.08 0.1, 3.31 0.06 C3.53 0.02, 3.77 0, 4 0 C4.23 0, 4.47 0.02, 4.69 0.06 C4.92 0.1, 5.15 0.16, 5.37 0.24 C5.59 0.32, 5.8 0.42, 6 0.54 C6.2 0.65, 6.39 0.79, 6.57 0.94 C6.75 1.08, 6.92 1.25, 7.06 1.43 C7.21 1.61, 7.35 1.8, 7.46 2 C7.58 2.2, 7.68 2.41, 7.76 2.63 C7.84 2.85, 7.9 3.08, 7.94 3.31 C7.98 3.53, 7.99 3.88, 8 4 C8.01 4.12, 8.01 3.88, 8 4" stroke="none" stroke-width="0" fill="var(--diagram-deemphasis, #8A7F72)"/><path d="M8 4 C8 4.23, 7.98 4.47, 7.94 4.69 C7.9 4.92, 7.84 5.15, 7.76 5.37 C7.68 5.59, 7.58 5.8, 7.46 6 C7.35 6.2, 7.21 6.39, 7.06 6.57 C6.92 6.75, 6.75 6.92, 6.57 7.06 C6.39 7.21, 6.2 7.35, 6 7.46 C5.8 7.58, 5.59 7.68, 5.37 7.76 C5.15 7.84, 4.92 7.9, 4.69 7.94 C4.47 7.98, 4.23 8, 4 8 C3.77 8, 3.53 7.98, 3.31 7.94 C3.08 7.9, 2.85 7.84, 2.63 7.76 C2.41 7.68, 2.2 7.58, 2 7.46 C1.8 7.35, 1.61 7.21, 1.43 7.06 C1.25 6.92, 1.08 6.75, 0.94 6.57 C0.79 6.39, 0.65 6.2, 0.54 6 C0.42 5.8, 0.32 5.59, 0.24 5.37 C0.16 5.15, 0.1 4.92, 0.06 4.69 C0.02 4.47, 0 4.23, 0 4 C0 3.77, 0.02 3.53, 0.06 3.31 C0.1 3.08, 0.16 2.85, 0.24 2.63 C0.32 2.41, 0.42 2.2, 0.54 2 C0.65 1.8, 0.79 1.61, 0.94 1.43 C1.08 1.25, 1.25 1.08, 1.43 0.94 C1.61 0.79, 1.8 0.65, 2 0.54 C2.2 0.42, 2.41 0.32, 2.63 0.24 C2.85 0.16, 3.08 0.1, 3.31 0.06 C3.53 0.02, 3.77 0, 4 0 C4.23 0, 4.47 0.02, 4.69 0.06 C4.92 0.1, 5.15 0.16, 5.37 0.24 C5.59 0.32, 5.8 0.42, 6 0.54 C6.2 0.65, 6.39 0.79, 6.57 0.94 C6.75 1.08, 6.92 1.25, 7.06 1.43 C7.21 1.61, 7.35 1.8, 7.46 2 C7.58 2.2, 7.68 2.41, 7.76 2.63 C7.84 2.85, 7.9 3.08, 7.94 3.31 C7.98 3.53, 7.99 3.88, 8 4 C8.01 4.12, 8.01 3.88, 8 4" stroke="var(--diagram-deemphasis, #8A7F72)" stroke-width="1.4" fill="none"/></g><g transform="translate(63 150) rotate(0 114.5 14)"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, sans-serif, Segoe UI Emoji" font-size="20px" fill="var(--diagram-ink, #1B1F23)" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">Authorizer (object)</text></g><g transform="translate(356 153) rotate(0 199 11)"><text x="0" y="14.096" font-family="Excalifont, Xiaolai, sans-serif, Segoe UI Emoji" font-size="16px" fill="var(--diagram-deemphasis, #8A7F72)" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">-> Role-based access control per operation</text></g></svg>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "meadow",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.44",
|
|
4
4
|
"description": "A data access library.",
|
|
5
5
|
"main": "source/Meadow.js",
|
|
6
6
|
"scripts": {
|
|
@@ -28,6 +28,11 @@
|
|
|
28
28
|
"docker-postgresql-status": "./scripts/postgresql-test-db.sh status",
|
|
29
29
|
"test-postgresql": "./scripts/postgresql-test-db.sh start && npx quack test -g Meadow-Provider-PostgreSQL",
|
|
30
30
|
"test-postgresql-all": "./scripts/postgresql-test-db.sh start && npx mocha -u tdd --exit -R spec",
|
|
31
|
+
"docker-oracle-start": "./scripts/oracle-test-db.sh start",
|
|
32
|
+
"docker-oracle-stop": "./scripts/oracle-test-db.sh stop",
|
|
33
|
+
"docker-oracle-status": "./scripts/oracle-test-db.sh status",
|
|
34
|
+
"test-oracle": "./scripts/oracle-test-db.sh start && npx quack test -g Meadow-Provider-Oracle",
|
|
35
|
+
"test-oracle-all": "./scripts/oracle-test-db.sh start && npx mocha -u tdd --exit -R spec",
|
|
31
36
|
"docker-mongodb-start": "./scripts/mongodb-test-db.sh start",
|
|
32
37
|
"docker-mongodb-stop": "./scripts/mongodb-test-db.sh stop",
|
|
33
38
|
"docker-mongodb-status": "./scripts/mongodb-test-db.sh status",
|
|
@@ -43,7 +48,7 @@
|
|
|
43
48
|
"test-alasql": "npx quack test -g Meadow-Provider-ALASQL",
|
|
44
49
|
"test-sqlite-browser": "npx quack test -g Meadow-Provider-SQLiteBrowser",
|
|
45
50
|
"test-sqlite-browser-headless": "npx mocha -u tdd --exit --timeout 60000 test/Meadow-Provider-SQLiteBrowser-Headless_tests.js",
|
|
46
|
-
"test-all-providers": "./scripts/mysql-test-db.sh start && ./scripts/mssql-test-db.sh start && ./scripts/postgresql-test-db.sh start && ./scripts/mongodb-test-db.sh start && ./scripts/solr-test-db.sh start && ./scripts/dgraph-test-db.sh start && npx mocha -u tdd --exit -R spec",
|
|
51
|
+
"test-all-providers": "./scripts/mysql-test-db.sh start && ./scripts/mssql-test-db.sh start && ./scripts/postgresql-test-db.sh start && ./scripts/oracle-test-db.sh start && ./scripts/mongodb-test-db.sh start && ./scripts/solr-test-db.sh start && ./scripts/dgraph-test-db.sh start && npx mocha -u tdd --exit -R spec",
|
|
47
52
|
"docker-cleanup": "./scripts/meadow-test-cleanup.sh",
|
|
48
53
|
"test-cleanup": "./scripts/meadow-test-cleanup.sh"
|
|
49
54
|
},
|
|
@@ -82,27 +87,29 @@
|
|
|
82
87
|
"devDependencies": {
|
|
83
88
|
"alasql": "^4.17.0",
|
|
84
89
|
"dgraph-js-http": "^21.3.0",
|
|
85
|
-
"fable": "^3.1.
|
|
90
|
+
"fable": "^3.1.76",
|
|
86
91
|
"gulp-util": "^3.0.8",
|
|
87
92
|
"meadow-connection-dgraph": "^1.0.3",
|
|
88
93
|
"meadow-connection-mongodb": "^1.0.3",
|
|
89
94
|
"meadow-connection-mssql": "^1.0.23",
|
|
90
95
|
"meadow-connection-mysql": "^1.0.19",
|
|
91
|
-
"meadow-connection-
|
|
96
|
+
"meadow-connection-oracle": "^1.0.2",
|
|
97
|
+
"meadow-connection-postgresql": "^1.0.7",
|
|
92
98
|
"meadow-connection-rocksdb": "^1.0.0",
|
|
93
99
|
"meadow-connection-solr": "^1.0.3",
|
|
94
100
|
"meadow-connection-sqlite": "^1.0.20",
|
|
95
101
|
"meadow-connection-sqlite-browser": "^1.0.2",
|
|
96
102
|
"mongodb": "^6.12.0",
|
|
97
103
|
"mysql2": "^3.18.2",
|
|
98
|
-
"
|
|
104
|
+
"oracledb": "^6.10.0",
|
|
105
|
+
"pict-docuserve": "^1.4.19",
|
|
99
106
|
"puppeteer": "^24.38.0",
|
|
100
107
|
"quackage": "^1.3.0",
|
|
101
108
|
"solr-client": "^0.9.0"
|
|
102
109
|
},
|
|
103
110
|
"dependencies": {
|
|
104
111
|
"async": "3.2.6",
|
|
105
|
-
"foxhound": "^2.0.
|
|
112
|
+
"foxhound": "^2.0.29",
|
|
106
113
|
"is-my-json-valid": "2.20.6",
|
|
107
114
|
"simple-get": "^4.0.1"
|
|
108
115
|
}
|
|
@@ -496,6 +496,138 @@ function emitMSSQL()
|
|
|
496
496
|
return tmpOut.join('\n');
|
|
497
497
|
}
|
|
498
498
|
|
|
499
|
+
// ---------------------------------------------------------------------------
|
|
500
|
+
// Oracle emitter. Oracle has no CREATE TABLE IF NOT EXISTS; the docker script
|
|
501
|
+
// runs this seed once against a fresh container, so plain CREATE TABLE is fine.
|
|
502
|
+
// Output is sqlplus-friendly: SET DEFINE OFF stops the '&' in "Angels & Demons"
|
|
503
|
+
// from being read as a substitution variable, and WHENEVER SQLERROR EXIT
|
|
504
|
+
// FAILURE makes a bad statement fail the piped load. Identity columns + the
|
|
505
|
+
// 23ai multi-row VALUES clause keep it close to the other dialects.
|
|
506
|
+
// ---------------------------------------------------------------------------
|
|
507
|
+
function emitOracle()
|
|
508
|
+
{
|
|
509
|
+
const tmpOut = [];
|
|
510
|
+
tmpOut.push('-- Bookstore Schema and Seed Data for Meadow Oracle Tests');
|
|
511
|
+
tmpOut.push('-- Generated by scripts/bookstore-seed.js (GUIDs minted via fable-uuid)');
|
|
512
|
+
tmpOut.push('SET DEFINE OFF');
|
|
513
|
+
tmpOut.push('WHENEVER SQLERROR EXIT FAILURE');
|
|
514
|
+
tmpOut.push('');
|
|
515
|
+
tmpOut.push('CREATE TABLE Book');
|
|
516
|
+
tmpOut.push(' (');
|
|
517
|
+
tmpOut.push(' IDBook NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,');
|
|
518
|
+
tmpOut.push(' GUIDBook VARCHAR2(36) DEFAULT \'00000000-0000-0000-0000-000000000000\' NOT NULL,');
|
|
519
|
+
tmpOut.push(' CreateDate TIMESTAMP,');
|
|
520
|
+
tmpOut.push(' CreatingIDUser NUMBER DEFAULT 0 NOT NULL,');
|
|
521
|
+
tmpOut.push(' UpdateDate TIMESTAMP,');
|
|
522
|
+
tmpOut.push(' UpdatingIDUser NUMBER DEFAULT 0 NOT NULL,');
|
|
523
|
+
tmpOut.push(' Deleted NUMBER(1) DEFAULT 0 NOT NULL,');
|
|
524
|
+
tmpOut.push(' DeleteDate TIMESTAMP,');
|
|
525
|
+
tmpOut.push(' DeletingIDUser NUMBER DEFAULT 0 NOT NULL,');
|
|
526
|
+
tmpOut.push(' Title VARCHAR2(200) DEFAULT \' \' NOT NULL,');
|
|
527
|
+
tmpOut.push(' Type VARCHAR2(32) DEFAULT \' \' NOT NULL,');
|
|
528
|
+
tmpOut.push(' Genre VARCHAR2(128) DEFAULT \' \' NOT NULL,');
|
|
529
|
+
tmpOut.push(' ISBN VARCHAR2(64) DEFAULT \' \' NOT NULL,');
|
|
530
|
+
tmpOut.push(' Language VARCHAR2(12) DEFAULT \' \' NOT NULL,');
|
|
531
|
+
tmpOut.push(' ImageURL VARCHAR2(254) DEFAULT \' \' NOT NULL,');
|
|
532
|
+
tmpOut.push(' PublicationYear NUMBER DEFAULT 0 NOT NULL');
|
|
533
|
+
tmpOut.push(' );');
|
|
534
|
+
tmpOut.push('');
|
|
535
|
+
tmpOut.push('CREATE TABLE BookAuthorJoin');
|
|
536
|
+
tmpOut.push(' (');
|
|
537
|
+
tmpOut.push(' IDBookAuthorJoin NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,');
|
|
538
|
+
tmpOut.push(' GUIDBookAuthorJoin VARCHAR2(36) DEFAULT \'00000000-0000-0000-0000-000000000000\' NOT NULL,');
|
|
539
|
+
tmpOut.push(' IDBook NUMBER DEFAULT 0 NOT NULL,');
|
|
540
|
+
tmpOut.push(' IDAuthor NUMBER DEFAULT 0 NOT NULL');
|
|
541
|
+
tmpOut.push(' );');
|
|
542
|
+
tmpOut.push('');
|
|
543
|
+
tmpOut.push('CREATE TABLE Author');
|
|
544
|
+
tmpOut.push(' (');
|
|
545
|
+
tmpOut.push(' IDAuthor NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,');
|
|
546
|
+
tmpOut.push(' GUIDAuthor VARCHAR2(36) DEFAULT \'00000000-0000-0000-0000-000000000000\' NOT NULL,');
|
|
547
|
+
tmpOut.push(' CreateDate TIMESTAMP,');
|
|
548
|
+
tmpOut.push(' CreatingIDUser NUMBER DEFAULT 0 NOT NULL,');
|
|
549
|
+
tmpOut.push(' UpdateDate TIMESTAMP,');
|
|
550
|
+
tmpOut.push(' UpdatingIDUser NUMBER DEFAULT 0 NOT NULL,');
|
|
551
|
+
tmpOut.push(' Deleted NUMBER(1) DEFAULT 0 NOT NULL,');
|
|
552
|
+
tmpOut.push(' DeleteDate TIMESTAMP,');
|
|
553
|
+
tmpOut.push(' DeletingIDUser NUMBER DEFAULT 0 NOT NULL,');
|
|
554
|
+
tmpOut.push(' Name VARCHAR2(200) DEFAULT \' \' NOT NULL');
|
|
555
|
+
tmpOut.push(' );');
|
|
556
|
+
tmpOut.push('');
|
|
557
|
+
tmpOut.push('CREATE TABLE BookPrice');
|
|
558
|
+
tmpOut.push(' (');
|
|
559
|
+
tmpOut.push(' IDBookPrice NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,');
|
|
560
|
+
tmpOut.push(' GUIDBookPrice VARCHAR2(36) DEFAULT \'00000000-0000-0000-0000-000000000000\' NOT NULL,');
|
|
561
|
+
tmpOut.push(' CreateDate TIMESTAMP,');
|
|
562
|
+
tmpOut.push(' CreatingIDUser NUMBER DEFAULT 0 NOT NULL,');
|
|
563
|
+
tmpOut.push(' UpdateDate TIMESTAMP,');
|
|
564
|
+
tmpOut.push(' UpdatingIDUser NUMBER DEFAULT 0 NOT NULL,');
|
|
565
|
+
tmpOut.push(' Deleted NUMBER(1) DEFAULT 0 NOT NULL,');
|
|
566
|
+
tmpOut.push(' DeleteDate TIMESTAMP,');
|
|
567
|
+
tmpOut.push(' DeletingIDUser NUMBER DEFAULT 0 NOT NULL,');
|
|
568
|
+
tmpOut.push(' Price NUMBER(8,2),');
|
|
569
|
+
tmpOut.push(' StartDate TIMESTAMP,');
|
|
570
|
+
tmpOut.push(' EndDate TIMESTAMP,');
|
|
571
|
+
tmpOut.push(' Discountable NUMBER(1) DEFAULT 0 NOT NULL,');
|
|
572
|
+
tmpOut.push(' CouponCode VARCHAR2(16) DEFAULT \' \' NOT NULL,');
|
|
573
|
+
tmpOut.push(' IDBook NUMBER DEFAULT 0 NOT NULL');
|
|
574
|
+
tmpOut.push(' );');
|
|
575
|
+
tmpOut.push('');
|
|
576
|
+
tmpOut.push('CREATE TABLE Review');
|
|
577
|
+
tmpOut.push(' (');
|
|
578
|
+
tmpOut.push(' IDReviews NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,');
|
|
579
|
+
tmpOut.push(' GUIDReviews VARCHAR2(36) DEFAULT \'00000000-0000-0000-0000-000000000000\' NOT NULL,');
|
|
580
|
+
tmpOut.push(' CreateDate TIMESTAMP,');
|
|
581
|
+
tmpOut.push(' CreatingIDUser NUMBER DEFAULT 0 NOT NULL,');
|
|
582
|
+
tmpOut.push(' UpdateDate TIMESTAMP,');
|
|
583
|
+
tmpOut.push(' UpdatingIDUser NUMBER DEFAULT 0 NOT NULL,');
|
|
584
|
+
tmpOut.push(' Deleted NUMBER(1) DEFAULT 0 NOT NULL,');
|
|
585
|
+
tmpOut.push(' DeleteDate TIMESTAMP,');
|
|
586
|
+
tmpOut.push(' DeletingIDUser NUMBER DEFAULT 0 NOT NULL,');
|
|
587
|
+
tmpOut.push(' Text CLOB,');
|
|
588
|
+
tmpOut.push(' Rating NUMBER DEFAULT 0 NOT NULL,');
|
|
589
|
+
tmpOut.push(' IDBook NUMBER DEFAULT 0 NOT NULL');
|
|
590
|
+
tmpOut.push(' );');
|
|
591
|
+
tmpOut.push('');
|
|
592
|
+
tmpOut.push('-- Seed Data: First 20 books from books.csv');
|
|
593
|
+
tmpOut.push('-- Inserted in CSV order so IDBook matches CSV row number');
|
|
594
|
+
tmpOut.push('');
|
|
595
|
+
tmpOut.push('INSERT INTO Book (GUIDBook, Title, Type, Genre, ISBN, Language, ImageURL, PublicationYear, CreateDate, CreatingIDUser, UpdateDate, UpdatingIDUser) VALUES');
|
|
596
|
+
const tmpBookRows = BOOKS.map((pBook) =>
|
|
597
|
+
{
|
|
598
|
+
return ' (' + [
|
|
599
|
+
sqlQuote(tmpUUID.getUUID()),
|
|
600
|
+
sqlQuote(pBook.Title),
|
|
601
|
+
sqlQuote(pBook.Type),
|
|
602
|
+
sqlQuote(pBook.Genre),
|
|
603
|
+
sqlQuote(pBook.ISBN),
|
|
604
|
+
sqlQuote(pBook.Language),
|
|
605
|
+
sqlQuote(pBook.ImageURL),
|
|
606
|
+
pBook.PublicationYear,
|
|
607
|
+
'SYS_EXTRACT_UTC(SYSTIMESTAMP)', '99999', 'SYS_EXTRACT_UTC(SYSTIMESTAMP)', '99999'
|
|
608
|
+
].join(', ') + ')';
|
|
609
|
+
});
|
|
610
|
+
tmpOut.push(tmpBookRows.join(',\n') + ';');
|
|
611
|
+
tmpOut.push('');
|
|
612
|
+
tmpOut.push('-- Seed Data: Authors for the first 20 books');
|
|
613
|
+
tmpOut.push('');
|
|
614
|
+
tmpOut.push('INSERT INTO Author (GUIDAuthor, Name, CreateDate, CreatingIDUser, UpdateDate, UpdatingIDUser) VALUES');
|
|
615
|
+
const tmpAuthorRows = AUTHORS.map((pName) =>
|
|
616
|
+
{
|
|
617
|
+
return ' (' + [
|
|
618
|
+
sqlQuote(tmpUUID.getUUID()),
|
|
619
|
+
sqlQuote(pName),
|
|
620
|
+
'SYS_EXTRACT_UTC(SYSTIMESTAMP)', '99999', 'SYS_EXTRACT_UTC(SYSTIMESTAMP)', '99999'
|
|
621
|
+
].join(', ') + ')';
|
|
622
|
+
});
|
|
623
|
+
tmpOut.push(tmpAuthorRows.join(',\n') + ';');
|
|
624
|
+
tmpOut.push('');
|
|
625
|
+
tmpOut.push('COMMIT;');
|
|
626
|
+
tmpOut.push('EXIT');
|
|
627
|
+
tmpOut.push('');
|
|
628
|
+
return tmpOut.join('\n');
|
|
629
|
+
}
|
|
630
|
+
|
|
499
631
|
// ---------------------------------------------------------------------------
|
|
500
632
|
// CLI
|
|
501
633
|
// ---------------------------------------------------------------------------
|
|
@@ -532,7 +664,10 @@ switch (tmpDialect)
|
|
|
532
664
|
case 'mssql':
|
|
533
665
|
process.stdout.write(emitMSSQL());
|
|
534
666
|
break;
|
|
667
|
+
case 'oracle':
|
|
668
|
+
process.stdout.write(emitOracle());
|
|
669
|
+
break;
|
|
535
670
|
default:
|
|
536
|
-
process.stderr.write('Usage: bookstore-seed.js --dialect <mysql|postgresql|mssql>\n');
|
|
671
|
+
process.stderr.write('Usage: bookstore-seed.js --dialect <mysql|postgresql|mssql|oracle>\n');
|
|
537
672
|
process.exit(1);
|
|
538
673
|
}
|
|
@@ -14,6 +14,7 @@ echo ""
|
|
|
14
14
|
"${SCRIPT_DIR}/mysql-test-db.sh" stop
|
|
15
15
|
"${SCRIPT_DIR}/mssql-test-db.sh" stop
|
|
16
16
|
"${SCRIPT_DIR}/postgresql-test-db.sh" stop
|
|
17
|
+
"${SCRIPT_DIR}/oracle-test-db.sh" stop
|
|
17
18
|
"${SCRIPT_DIR}/mongodb-test-db.sh" stop
|
|
18
19
|
"${SCRIPT_DIR}/solr-test-db.sh" stop
|
|
19
20
|
"${SCRIPT_DIR}/dgraph-test-db.sh" stop
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Oracle Test Database Management Script
|
|
3
|
+
#
|
|
4
|
+
# Usage:
|
|
5
|
+
# ./scripts/oracle-test-db.sh start - Start Oracle container, load schema and seed data
|
|
6
|
+
# ./scripts/oracle-test-db.sh stop - Stop and remove the container
|
|
7
|
+
# ./scripts/oracle-test-db.sh status - Check if the container is running
|
|
8
|
+
#
|
|
9
|
+
# Uses gvenzl/oracle-free (Oracle Database 23ai Free — no license required,
|
|
10
|
+
# multi-arch so it runs natively on Apple Silicon). gvenzl auto-creates the
|
|
11
|
+
# APP_USER in its own schema inside the FREEPDB1 pluggable database.
|
|
12
|
+
#
|
|
13
|
+
# The container settings match the test configuration in
|
|
14
|
+
# test/Meadow-Provider-Oracle_tests.js and meadow-connection-oracle:
|
|
15
|
+
# Host: 127.0.0.1, Port: 21521, Service: FREEPDB1
|
|
16
|
+
# User: bookstore, Password: Retold1234567890!
|
|
17
|
+
|
|
18
|
+
CONTAINER_NAME="meadow-oracle-test"
|
|
19
|
+
ORACLE_USER="bookstore"
|
|
20
|
+
ORACLE_PASSWORD="Retold1234567890!"
|
|
21
|
+
ORACLE_SERVICE="FREEPDB1"
|
|
22
|
+
ORACLE_PORT="21521"
|
|
23
|
+
ORACLE_IMAGE="gvenzl/oracle-free:23-slim"
|
|
24
|
+
|
|
25
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
26
|
+
SEED_GENERATOR="${SCRIPT_DIR}/bookstore-seed.js"
|
|
27
|
+
|
|
28
|
+
start_oracle() {
|
|
29
|
+
# Check if container already exists
|
|
30
|
+
if docker ps -a --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
|
|
31
|
+
if docker ps --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
|
|
32
|
+
echo "Oracle test container is already running."
|
|
33
|
+
return 0
|
|
34
|
+
else
|
|
35
|
+
echo "Removing stopped container..."
|
|
36
|
+
docker rm "${CONTAINER_NAME}" > /dev/null 2>&1
|
|
37
|
+
fi
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
echo "Starting Oracle test container (first boot pulls the image and initializes the DB; this can take several minutes)..."
|
|
41
|
+
docker run -d \
|
|
42
|
+
--name "${CONTAINER_NAME}" \
|
|
43
|
+
-e ORACLE_PASSWORD="${ORACLE_PASSWORD}" \
|
|
44
|
+
-e APP_USER="${ORACLE_USER}" \
|
|
45
|
+
-e APP_USER_PASSWORD="${ORACLE_PASSWORD}" \
|
|
46
|
+
-p "${ORACLE_PORT}:1521" \
|
|
47
|
+
"${ORACLE_IMAGE}"
|
|
48
|
+
|
|
49
|
+
if [ $? -ne 0 ]; then
|
|
50
|
+
echo "ERROR: Failed to start Oracle container."
|
|
51
|
+
exit 1
|
|
52
|
+
fi
|
|
53
|
+
|
|
54
|
+
echo "Waiting for Oracle to accept connections (gvenzl healthcheck)..."
|
|
55
|
+
RETRIES=120
|
|
56
|
+
until docker exec "${CONTAINER_NAME}" healthcheck.sh > /dev/null 2>&1; do
|
|
57
|
+
RETRIES=$((RETRIES - 1))
|
|
58
|
+
if [ $RETRIES -le 0 ]; then
|
|
59
|
+
echo "ERROR: Oracle failed to become ready in time."
|
|
60
|
+
docker logs "${CONTAINER_NAME}" 2>&1 | tail -20
|
|
61
|
+
exit 1
|
|
62
|
+
fi
|
|
63
|
+
echo " ...waiting (${RETRIES} retries left)"
|
|
64
|
+
sleep 5
|
|
65
|
+
done
|
|
66
|
+
|
|
67
|
+
# Load bookstore schema and seed data (GUIDs minted at generation time via fable-uuid)
|
|
68
|
+
if [ -f "${SEED_GENERATOR}" ]; then
|
|
69
|
+
echo "Loading bookstore schema and seed data..."
|
|
70
|
+
node "${SEED_GENERATOR}" --dialect oracle | \
|
|
71
|
+
docker exec -i "${CONTAINER_NAME}" sqlplus -S "${ORACLE_USER}/${ORACLE_PASSWORD}@//localhost:1521/${ORACLE_SERVICE}"
|
|
72
|
+
if [ $? -ne 0 ]; then
|
|
73
|
+
echo "WARNING: Failed to load seed data. Tests requiring pre-populated data may fail."
|
|
74
|
+
else
|
|
75
|
+
echo "Bookstore schema and seed data loaded successfully."
|
|
76
|
+
fi
|
|
77
|
+
else
|
|
78
|
+
echo "WARNING: Seed generator not found at ${SEED_GENERATOR}. Skipping schema/data loading."
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
echo ""
|
|
82
|
+
echo "Oracle test database is ready!"
|
|
83
|
+
echo " Container: ${CONTAINER_NAME}"
|
|
84
|
+
echo " Host: 127.0.0.1:${ORACLE_PORT}"
|
|
85
|
+
echo " Service: ${ORACLE_SERVICE}"
|
|
86
|
+
echo " User: ${ORACLE_USER}"
|
|
87
|
+
echo " Password: ${ORACLE_PASSWORD}"
|
|
88
|
+
echo ""
|
|
89
|
+
echo "Run tests with: npm test"
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
stop_oracle() {
|
|
93
|
+
if docker ps -a --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
|
|
94
|
+
echo "Stopping and removing Oracle test container..."
|
|
95
|
+
docker stop "${CONTAINER_NAME}" > /dev/null 2>&1
|
|
96
|
+
docker rm "${CONTAINER_NAME}" > /dev/null 2>&1
|
|
97
|
+
echo "Oracle test container removed."
|
|
98
|
+
else
|
|
99
|
+
echo "No Oracle test container found."
|
|
100
|
+
fi
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
status_oracle() {
|
|
104
|
+
if docker ps --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
|
|
105
|
+
echo "Oracle test container is running."
|
|
106
|
+
docker ps --filter "name=${CONTAINER_NAME}" --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
|
|
107
|
+
elif docker ps -a --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
|
|
108
|
+
echo "Oracle test container exists but is stopped."
|
|
109
|
+
else
|
|
110
|
+
echo "Oracle test container is not running."
|
|
111
|
+
fi
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
case "${1}" in
|
|
115
|
+
start)
|
|
116
|
+
start_oracle
|
|
117
|
+
;;
|
|
118
|
+
stop)
|
|
119
|
+
stop_oracle
|
|
120
|
+
;;
|
|
121
|
+
status)
|
|
122
|
+
status_oracle
|
|
123
|
+
;;
|
|
124
|
+
*)
|
|
125
|
+
echo "Usage: $0 {start|stop|status}"
|
|
126
|
+
exit 1
|
|
127
|
+
;;
|
|
128
|
+
esac
|
|
@@ -19,10 +19,10 @@ var MeadowProvider = function()
|
|
|
19
19
|
|
|
20
20
|
var _Dialect = 'MeadowEndpoints';
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
var
|
|
22
|
+
// Static fallback configuration — used when no live connection instance
|
|
23
|
+
// is bound (standalone DAL usage). Settings are STATIC boot config:
|
|
24
|
+
// host/port/prefix only, never session state.
|
|
25
|
+
var _StaticEndpointSettings = (_Fable.settings.hasOwnProperty('MeadowEndpoints')) ? JSON.parse(JSON.stringify(_Fable.settings.MeadowEndpoints)) : (
|
|
26
26
|
{
|
|
27
27
|
ServerProtocol: 'http',
|
|
28
28
|
ServerAddress: '127.0.0.1',
|
|
@@ -31,9 +31,32 @@ var MeadowProvider = function()
|
|
|
31
31
|
}
|
|
32
32
|
)
|
|
33
33
|
|
|
34
|
+
// Instance-driven configuration (preferred) — the same convention the
|
|
35
|
+
// SQL providers use (e.g. _Fable.MeadowMySQLProvider): the DAL's fable
|
|
36
|
+
// carries the live connection instance, which OWNS both the connection
|
|
37
|
+
// parameters and the session state (headers/cookies). Reading it per
|
|
38
|
+
// request means post-connect authentication and later cookie rotation
|
|
39
|
+
// always apply to the requests this provider makes.
|
|
40
|
+
var getConnectionInstance = function()
|
|
41
|
+
{
|
|
42
|
+
return (typeof(_Fable.MeadowMeadowEndpointsProvider) === 'object' && _Fable.MeadowMeadowEndpointsProvider !== null)
|
|
43
|
+
? _Fable.MeadowMeadowEndpointsProvider : null;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
var getEndpointSettings = function()
|
|
47
|
+
{
|
|
48
|
+
let tmpInstance = getConnectionInstance();
|
|
49
|
+
if (tmpInstance && typeof(tmpInstance.settings) === 'object' && tmpInstance.settings !== null)
|
|
50
|
+
{
|
|
51
|
+
return tmpInstance.settings;
|
|
52
|
+
}
|
|
53
|
+
return _StaticEndpointSettings;
|
|
54
|
+
};
|
|
55
|
+
|
|
34
56
|
var buildURL = function(pAddress)
|
|
35
57
|
{
|
|
36
|
-
|
|
58
|
+
let tmpEndpointSettings = getEndpointSettings();
|
|
59
|
+
return `${tmpEndpointSettings.ServerProtocol}://${tmpEndpointSettings.ServerAddress}:${tmpEndpointSettings.ServerPort}/${tmpEndpointSettings.ServerEndpointPrefix}${pAddress}`;
|
|
37
60
|
};
|
|
38
61
|
|
|
39
62
|
var buildRequestOptions = function(pQuery)
|
|
@@ -46,13 +69,19 @@ var MeadowProvider = function()
|
|
|
46
69
|
|
|
47
70
|
let tmpURL = buildURL(pQuery.query.body);
|
|
48
71
|
|
|
72
|
+
let tmpInstance = getConnectionInstance();
|
|
73
|
+
let tmpHeaders = (tmpInstance && typeof(tmpInstance.headers) === 'object' && tmpInstance.headers !== null)
|
|
74
|
+
? tmpInstance.headers : {};
|
|
75
|
+
let tmpCookies = (tmpInstance && Array.isArray(tmpInstance.cookies))
|
|
76
|
+
? tmpInstance.cookies : [];
|
|
77
|
+
|
|
49
78
|
let tmpRequestOptions = (
|
|
50
79
|
{
|
|
51
80
|
url: tmpURL,
|
|
52
|
-
headers: _Fable.Utility.extend({cookie: ''},
|
|
81
|
+
headers: _Fable.Utility.extend({cookie: ''}, tmpHeaders)
|
|
53
82
|
});
|
|
54
83
|
|
|
55
|
-
tmpRequestOptions.headers.cookie =
|
|
84
|
+
tmpRequestOptions.headers.cookie = tmpCookies.join(';');
|
|
56
85
|
|
|
57
86
|
|
|
58
87
|
if (pQuery.logLevel > 0 ||
|
|
@@ -305,7 +305,11 @@ var MeadowProvider = function ()
|
|
|
305
305
|
executeStatement(pQuery.query.body, tmpBinds, function (pError, pDBResult)
|
|
306
306
|
{
|
|
307
307
|
tmpResult.error = pError;
|
|
308
|
-
|
|
308
|
+
// The Meadow Update behavior requires result.value to be an
|
|
309
|
+
// object; oracledb's UPDATE result has no rows array (no
|
|
310
|
+
// RETURNING), so mirror the PostgreSQL provider and expose an
|
|
311
|
+
// (empty) array. The post-update Read supplies the record.
|
|
312
|
+
tmpResult.value = (pDBResult && pDBResult.rows) ? pDBResult.rows : [];
|
|
309
313
|
tmpResult.executed = true;
|
|
310
314
|
return fCallback();
|
|
311
315
|
});
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Meadow MeadowEndpoints provider — instance-driven configuration tests.
|
|
3
|
+
*
|
|
4
|
+
* The provider follows the SQL-provider convention: the DAL's fable carries
|
|
5
|
+
* the live connection instance at fable.MeadowMeadowEndpointsProvider, which
|
|
6
|
+
* OWNS the connection parameters and the session state (headers/cookies) —
|
|
7
|
+
* read per request, so post-connect authentication and cookie rotation
|
|
8
|
+
* always apply. fable.settings.MeadowEndpoints remains the STATIC fallback
|
|
9
|
+
* for standalone DAL usage (host/port/prefix only; settings carry no session
|
|
10
|
+
* state).
|
|
11
|
+
*
|
|
12
|
+
* npx mocha test/Meadow-Provider-MeadowEndpoints-Session_tests.js -u tdd --exit
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const Chai = require('chai');
|
|
16
|
+
const Expect = Chai.expect;
|
|
17
|
+
const libHttp = require('http');
|
|
18
|
+
const libFable = require('fable');
|
|
19
|
+
const libMeadow = require('../source/Meadow.js');
|
|
20
|
+
|
|
21
|
+
const ANIMAL_SCHEMA = require('./Animal.json');
|
|
22
|
+
|
|
23
|
+
let _Server = null;
|
|
24
|
+
let _ServerPort = 0;
|
|
25
|
+
let _LastRequest = null;
|
|
26
|
+
|
|
27
|
+
function startStubAPI()
|
|
28
|
+
{
|
|
29
|
+
return new Promise((fResolve) =>
|
|
30
|
+
{
|
|
31
|
+
_Server = libHttp.createServer((pRequest, pResponse) =>
|
|
32
|
+
{
|
|
33
|
+
_LastRequest = { URL: pRequest.url, Cookie: pRequest.headers.cookie || '', Headers: pRequest.headers };
|
|
34
|
+
pResponse.writeHead(200, { 'Content-Type': 'application/json' });
|
|
35
|
+
pResponse.end(JSON.stringify([ { IDAnimal: 1, Name: 'Stub' } ]));
|
|
36
|
+
});
|
|
37
|
+
_Server.listen(0, '127.0.0.1', () =>
|
|
38
|
+
{
|
|
39
|
+
_ServerPort = _Server.address().port;
|
|
40
|
+
fResolve();
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function serverSettings()
|
|
46
|
+
{
|
|
47
|
+
return { ServerProtocol: 'http', ServerAddress: '127.0.0.1', ServerPort: String(_ServerPort), ServerEndpointPrefix: '1.0/' };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function buildDAL(pBoundInstance, pStaticSettings)
|
|
51
|
+
{
|
|
52
|
+
let tmpFable = new libFable(
|
|
53
|
+
{
|
|
54
|
+
Product: 'MeadowEndpointsInstanceTest',
|
|
55
|
+
LogStreams: [ { streamtype: 'console', level: 'fatal' } ],
|
|
56
|
+
MeadowEndpoints: pStaticSettings
|
|
57
|
+
});
|
|
58
|
+
if (pBoundInstance)
|
|
59
|
+
{
|
|
60
|
+
// The binding the dynamic-endpoint layer performs for live connections.
|
|
61
|
+
tmpFable.MeadowMeadowEndpointsProvider = pBoundInstance;
|
|
62
|
+
}
|
|
63
|
+
let tmpMeadow = libMeadow.new(tmpFable).loadFromPackageObject(ANIMAL_SCHEMA);
|
|
64
|
+
tmpMeadow.setProvider('MeadowEndpoints');
|
|
65
|
+
return tmpMeadow;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function readAnimals(pDAL)
|
|
69
|
+
{
|
|
70
|
+
return new Promise((fResolve) =>
|
|
71
|
+
{
|
|
72
|
+
pDAL.doReads(pDAL.query.clone().setCap(1), (pError, pQuery, pRecords) => fResolve({ Error: pError, Records: pRecords }));
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
suite('MeadowEndpoints provider instance-driven configuration', function ()
|
|
77
|
+
{
|
|
78
|
+
suiteSetup(async function () { await startStubAPI(); });
|
|
79
|
+
suiteTeardown(function () { if (_Server) { _Server.close(); } });
|
|
80
|
+
setup(function () { _LastRequest = null; });
|
|
81
|
+
|
|
82
|
+
test('a bound instance supplies connection parameters AND session cookies', async function ()
|
|
83
|
+
{
|
|
84
|
+
const tmpInstance = { settings: serverSettings(), headers: {}, cookies: [ 'UserSession=from-the-connector' ] };
|
|
85
|
+
await readAnimals(buildDAL(tmpInstance));
|
|
86
|
+
Expect(_LastRequest.Cookie).to.equal('UserSession=from-the-connector');
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
test('cookies set on the instance AFTER DAL init apply (post-connect auth)', async function ()
|
|
90
|
+
{
|
|
91
|
+
const tmpInstance = { settings: serverSettings(), headers: {}, cookies: [] };
|
|
92
|
+
const tmpDAL = buildDAL(tmpInstance);
|
|
93
|
+
tmpInstance.cookies.push('UserSession=established-later');
|
|
94
|
+
await readAnimals(tmpDAL);
|
|
95
|
+
Expect(_LastRequest.Cookie).to.equal('UserSession=established-later');
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
test('cookie ROTATION on the instance is visible on the next request', async function ()
|
|
99
|
+
{
|
|
100
|
+
const tmpInstance = { settings: serverSettings(), headers: {}, cookies: [ 'UserSession=first' ] };
|
|
101
|
+
const tmpDAL = buildDAL(tmpInstance);
|
|
102
|
+
await readAnimals(tmpDAL);
|
|
103
|
+
Expect(_LastRequest.Cookie).to.equal('UserSession=first');
|
|
104
|
+
tmpInstance.cookies.length = 0;
|
|
105
|
+
tmpInstance.cookies.push('UserSession=rotated');
|
|
106
|
+
await readAnimals(tmpDAL);
|
|
107
|
+
Expect(_LastRequest.Cookie).to.equal('UserSession=rotated');
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test('instance headers ride along with requests', async function ()
|
|
111
|
+
{
|
|
112
|
+
const tmpInstance = { settings: serverSettings(), headers: { 'x-service-trust': 'instance-header' }, cookies: [] };
|
|
113
|
+
await readAnimals(buildDAL(tmpInstance));
|
|
114
|
+
Expect(_LastRequest.Headers['x-service-trust']).to.equal('instance-header');
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test('without a bound instance, static settings supply the URL and requests are anonymous', async function ()
|
|
118
|
+
{
|
|
119
|
+
const tmpOutcome = await readAnimals(buildDAL(null, serverSettings()));
|
|
120
|
+
Expect(_LastRequest.Cookie).to.equal('');
|
|
121
|
+
Expect(Array.isArray(tmpOutcome.Records)).to.equal(true);
|
|
122
|
+
});
|
|
123
|
+
});
|