├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── badges └── coverage.svg ├── coverage ├── clover.xml ├── coverage-final.json ├── lcov-report │ ├── action.ts.html │ ├── base.css │ ├── block-navigation.js │ ├── event.ts.html │ ├── favicon.png │ ├── index.html │ ├── prettify.css │ ├── prettify.js │ ├── sort-arrow-sprite.png │ ├── sorter.js │ └── types.ts.html └── lcov.info ├── jest.config.js ├── lib ├── action.d.ts ├── action.js ├── event.d.ts ├── event.js ├── index.d.ts ├── index.js ├── types.d.ts └── types.js ├── package-lock.json ├── package.json ├── src ├── action.ts ├── event.ts ├── index.ts └── types.ts ├── tests ├── action.test.ts └── event.test.ts ├── tsconfig.json └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | tests/ 2 | .git 3 | .npmrc 4 | coverage/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2020 Boštjan Cigan 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Hasura Parser 2 | 3 | ![npm version](https://img.shields.io/npm/v/%40snotra/hasura-parser?logo=npm&label=npm%20package&color=rgb(68%2C%20204%2C%2017)) 4 | ![Coverage](badges/coverage.svg) 5 | ![License](https://img.shields.io/github/license/snotra-org/hasura-parser?color=rgba(0%2C126%2C198)) 6 | 7 | An easy utility library for parsing data from Hasura events and actions. 8 | 9 | ## Getting started 10 | 11 | First install the package. 12 | 13 | ```bash 14 | yarn add @snotra/hasura-parser 15 | npm install @snotra/hasura-parser 16 | ``` 17 | 18 | ## Actions 19 | 20 | To use the Action Parser you can either import ActionParser or require the whole package. 21 | 22 | ```javascript 23 | import { ActionParser } from '@snotra/hasura-parser' 24 | 25 | // Data is from your request body 26 | const actionParser = new ActionParser( data ) 27 | ``` 28 | 29 | ### Parsing data 30 | 31 | To get the data you need, just pass in the keys of the arguments you want: 32 | 33 | ```javascript 34 | const data = actionParser.getData( "id", "type", "user" ) 35 | ``` 36 | 37 | This will give you the following response: 38 | 39 | ```javascript 40 | { 41 | "id": , 42 | "type": , 43 | "user": null 44 | } 45 | ``` 46 | 47 | If the value is not found a `null` will be returned in its place. 48 | 49 | If you want to get all the data in its raw form, you can issue the following call: 50 | 51 | ```javascript 52 | const data = actionParser.getRawData() 53 | ``` 54 | 55 | This will give you all the values that were passed in by Hasura. 56 | 57 | ### Getting session variables 58 | 59 | Single session variable: 60 | 61 | ```javascript 62 | const userId = actionParser.getSessionVariable( "x-hasura-user-id" ) 63 | ``` 64 | 65 | This will either give you the value of the session variable or just `null` if it is not set. 66 | 67 | All session variables: 68 | 69 | ```javascript 70 | const sessionVariables = actionParser.getSessionVariables() 71 | ``` 72 | 73 | ### Other data 74 | 75 | Action name: 76 | 77 | ```javascript 78 | const sessionVariables = actionParser.getActionName() 79 | ``` 80 | 81 | ## Events 82 | 83 | To use the Events Parser you can either import EventParser or require the whole package. 84 | 85 | ```javascript 86 | import { EventParser } from '@snotra/hasura-parser' 87 | 88 | // Data is from your request body 89 | const eventParser = new EventParser( data ) 90 | ``` 91 | 92 | ### Parsing data 93 | 94 | To get the data you need, just pass in the keys of the arguments you want: 95 | 96 | ```javascript 97 | const data = eventParser.getData( "id", "type", "user" ) 98 | ``` 99 | 100 | The response depends on the event type, if it is an INSERT, DELETE or MANUAL operation you will receive the following response: 101 | 102 | ```javascript 103 | { 104 | "id": , 105 | "type": , 106 | "user": null 107 | } 108 | ``` 109 | 110 | If the value is not found a `null` will be returned in its place. 111 | 112 | If it is an UPDATE operation, the object will contain the old and new values: 113 | 114 | ```javascript 115 | { 116 | "old": { 117 | "id": , 118 | "type": , 119 | "user": null 120 | }, 121 | "new": { 122 | "id": , 123 | "type": , 124 | "user": null 125 | } 126 | } 127 | ``` 128 | 129 | If you want to get all the data in its raw form, you can issue the following calls: 130 | 131 | ```javascript 132 | const oldData = eventParser.getOldData() 133 | const newData = eventParser.getNewData() 134 | ``` 135 | 136 | Depending on the event type, old or new can be `null`. 137 | 138 | This will give you all the values that were passed in by Hasura. 139 | 140 | ### Getting session variables 141 | 142 | Single session variable: 143 | 144 | ```javascript 145 | const userId = eventParser.getSessionVariable( "x-hasura-user-id" ) 146 | ``` 147 | 148 | This will either give you the value of the session variable or just `null` if it is not set. 149 | 150 | All session variables: 151 | 152 | ```javascript 153 | const sessionVariables = eventParser.getSessionVariables() 154 | ``` 155 | 156 | ### Other data 157 | 158 | Get ID of event: 159 | 160 | ```javascript 161 | const eventID = eventParser.getID() 162 | ``` 163 | 164 | Get trigger name (set in Hasura Console): 165 | 166 | ```javascript 167 | const triggerName = eventParser.getTriggerName() 168 | ``` 169 | 170 | Get schema name (the name of the schema that was affected by the event): 171 | 172 | ```javascript 173 | const schemaName = eventParser.getSchemaName() 174 | ``` 175 | 176 | Get table name (name of affected table by the event): 177 | 178 | ```javascript 179 | const tableName = eventParser.getTableName() 180 | ``` 181 | 182 | Get current retries and max retries (if this is set in the event in Hasura): 183 | 184 | ```javascript 185 | const currentRetry = eventParser.getCurrentRetry() 186 | const maxRetries = eventParser.getMaxRetries() 187 | ``` 188 | 189 | Operation type checking (INSERT, UPDATE, DELETE, MANUAL): 190 | 191 | ```javascript 192 | const isInsert = eventParser.isInsertOperation() // The following operations return a boolean value 193 | const isUpdate = eventParser.isUpdateOperation() 194 | const isDelete = eventParser.isDeleteOperation() 195 | const isManual = eventParser.isManualOperation() 196 | const operationType = eventParser.getOperationType() // Returns INSERT, UPDATE, DELETE or MANUAL 197 | ``` 198 | 199 | Timestamp of operation: 200 | 201 | ```javascript 202 | const timestamp = eventParser.getTimestamp() 203 | ``` 204 | 205 | Trace context: 206 | 207 | ```javascript 208 | const traceContextID = eventParser.getTraceContextID() 209 | const traceContextSpanID = eventParser.getTraceContextSpanID() 210 | ``` 211 | 212 | ## Contributions 213 | 214 | If you would like to make any contribution you are welcome to do so. -------------------------------------------------------------------------------- /badges/coverage.svg: -------------------------------------------------------------------------------- 1 | coveragecoverage100%100% -------------------------------------------------------------------------------- /coverage/clover.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /coverage/coverage-final.json: -------------------------------------------------------------------------------- 1 | {"/Users/bostjan/Projects/GraphQL/HasuraParser/src/action.ts": {"path":"/Users/bostjan/Projects/GraphQL/HasuraParser/src/action.ts","statementMap":{"0":{"start":{"line":5,"column":0},"end":{"line":5,"column":null}},"1":{"start":{"line":9,"column":2},"end":{"line":9,"column":null}},"2":{"start":{"line":16,"column":1},"end":{"line":18,"column":null}},"3":{"start":{"line":17,"column":2},"end":{"line":17,"column":null}},"4":{"start":{"line":23,"column":4},"end":{"line":25,"column":null}},"5":{"start":{"line":24,"column":2},"end":{"line":24,"column":null}},"6":{"start":{"line":30,"column":4},"end":{"line":32,"column":null}},"7":{"start":{"line":31,"column":8},"end":{"line":31,"column":null}},"8":{"start":{"line":39,"column":4},"end":{"line":61,"column":null}},"9":{"start":{"line":39,"column":13},"end":{"line":39,"column":35}},"10":{"start":{"line":42,"column":26},"end":{"line":42,"column":28}},"11":{"start":{"line":45,"column":8},"end":{"line":49,"column":null}},"12":{"start":{"line":46,"column":12},"end":{"line":46,"column":null}},"13":{"start":{"line":48,"column":12},"end":{"line":48,"column":null}},"14":{"start":{"line":51,"column":8},"end":{"line":58,"column":null}},"15":{"start":{"line":51,"column":22},"end":{"line":51,"column":23}},"16":{"start":{"line":52,"column":24},"end":{"line":52,"column":33}},"17":{"start":{"line":53,"column":12},"end":{"line":57,"column":null}},"18":{"start":{"line":54,"column":16},"end":{"line":54,"column":null}},"19":{"start":{"line":56,"column":16},"end":{"line":56,"column":null}},"20":{"start":{"line":60,"column":8},"end":{"line":60,"column":null}},"21":{"start":{"line":66,"column":4},"end":{"line":71,"column":null}},"22":{"start":{"line":67,"column":8},"end":{"line":69,"column":null}},"23":{"start":{"line":68,"column":12},"end":{"line":68,"column":null}},"24":{"start":{"line":70,"column":8},"end":{"line":70,"column":null}},"25":{"start":{"line":73,"column":0},"end":{"line":73,"column":null}},"26":{"start":{"line":75,"column":0},"end":{"line":75,"column":null}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":5,"column":0},"end":{"line":5,"column":null}},"loc":{"start":{"line":5,"column":0},"end":{"line":73,"column":null}}},"1":{"name":"ActionParser","decl":{"start":{"line":8,"column":1},"end":{"line":8,"column":14}},"loc":{"start":{"line":8,"column":35},"end":{"line":10,"column":5}}},"2":{"name":"(anonymous_2)","decl":{"start":{"line":16,"column":1},"end":{"line":16,"column":19}},"loc":{"start":{"line":16,"column":31},"end":{"line":18,"column":2}}},"3":{"name":"(anonymous_3)","decl":{"start":{"line":23,"column":4},"end":{"line":23,"column":23}},"loc":{"start":{"line":23,"column":4},"end":{"line":25,"column":5}}},"4":{"name":"(anonymous_4)","decl":{"start":{"line":30,"column":4},"end":{"line":30,"column":17}},"loc":{"start":{"line":30,"column":4},"end":{"line":32,"column":5}}},"5":{"name":"(anonymous_5)","decl":{"start":{"line":39,"column":4},"end":{"line":39,"column":11}},"loc":{"start":{"line":39,"column":4},"end":{"line":61,"column":5}}},"6":{"name":"(anonymous_6)","decl":{"start":{"line":66,"column":4},"end":{"line":66,"column":14}},"loc":{"start":{"line":66,"column":4},"end":{"line":71,"column":5}}}},"branchMap":{"0":{"loc":{"start":{"line":45,"column":8},"end":{"line":49,"column":null}},"type":"if","locations":[{"start":{"line":45,"column":8},"end":{"line":49,"column":null}},{"start":{"line":45,"column":8},"end":{"line":49,"column":null}}]},"1":{"loc":{"start":{"line":53,"column":12},"end":{"line":57,"column":null}},"type":"if","locations":[{"start":{"line":53,"column":12},"end":{"line":57,"column":null}},{"start":{"line":53,"column":12},"end":{"line":57,"column":null}}]},"2":{"loc":{"start":{"line":67,"column":8},"end":{"line":69,"column":null}},"type":"if","locations":[{"start":{"line":67,"column":8},"end":{"line":69,"column":null}},{"start":{"line":67,"column":8},"end":{"line":69,"column":null}}]}},"s":{"0":1,"1":7,"2":1,"3":2,"4":1,"5":1,"6":1,"7":1,"8":1,"9":10,"10":2,"11":2,"12":1,"13":1,"14":2,"15":2,"16":6,"17":6,"18":4,"19":2,"20":2,"21":1,"22":2,"23":1,"24":1,"25":1,"26":1},"f":{"0":1,"1":7,"2":2,"3":1,"4":1,"5":2,"6":2},"b":{"0":[1,1],"1":[4,2],"2":[1,1]}} 2 | ,"/Users/bostjan/Projects/GraphQL/HasuraParser/src/event.ts": {"path":"/Users/bostjan/Projects/GraphQL/HasuraParser/src/event.ts","statementMap":{"0":{"start":{"line":1,"column":0},"end":{"line":1,"column":null}},"1":{"start":{"line":7,"column":0},"end":{"line":7,"column":null}},"2":{"start":{"line":11,"column":2},"end":{"line":11,"column":null}},"3":{"start":{"line":17,"column":1},"end":{"line":19,"column":null}},"4":{"start":{"line":18,"column":2},"end":{"line":18,"column":null}},"5":{"start":{"line":24,"column":1},"end":{"line":26,"column":null}},"6":{"start":{"line":25,"column":2},"end":{"line":25,"column":null}},"7":{"start":{"line":31,"column":1},"end":{"line":33,"column":null}},"8":{"start":{"line":32,"column":2},"end":{"line":32,"column":null}},"9":{"start":{"line":38,"column":1},"end":{"line":40,"column":null}},"10":{"start":{"line":39,"column":2},"end":{"line":39,"column":null}},"11":{"start":{"line":45,"column":1},"end":{"line":47,"column":null}},"12":{"start":{"line":46,"column":2},"end":{"line":46,"column":null}},"13":{"start":{"line":53,"column":1},"end":{"line":55,"column":null}},"14":{"start":{"line":54,"column":2},"end":{"line":54,"column":null}},"15":{"start":{"line":60,"column":1},"end":{"line":62,"column":null}},"16":{"start":{"line":61,"column":2},"end":{"line":61,"column":null}},"17":{"start":{"line":67,"column":1},"end":{"line":69,"column":null}},"18":{"start":{"line":68,"column":2},"end":{"line":68,"column":null}},"19":{"start":{"line":74,"column":1},"end":{"line":76,"column":null}},"20":{"start":{"line":75,"column":2},"end":{"line":75,"column":null}},"21":{"start":{"line":81,"column":1},"end":{"line":83,"column":null}},"22":{"start":{"line":82,"column":2},"end":{"line":82,"column":null}},"23":{"start":{"line":88,"column":1},"end":{"line":90,"column":null}},"24":{"start":{"line":89,"column":2},"end":{"line":89,"column":null}},"25":{"start":{"line":95,"column":1},"end":{"line":97,"column":null}},"26":{"start":{"line":96,"column":2},"end":{"line":96,"column":null}},"27":{"start":{"line":102,"column":1},"end":{"line":104,"column":null}},"28":{"start":{"line":103,"column":2},"end":{"line":103,"column":null}},"29":{"start":{"line":109,"column":1},"end":{"line":111,"column":null}},"30":{"start":{"line":110,"column":2},"end":{"line":110,"column":null}},"31":{"start":{"line":116,"column":1},"end":{"line":118,"column":null}},"32":{"start":{"line":117,"column":2},"end":{"line":117,"column":null}},"33":{"start":{"line":123,"column":1},"end":{"line":125,"column":null}},"34":{"start":{"line":124,"column":2},"end":{"line":124,"column":null}},"35":{"start":{"line":130,"column":1},"end":{"line":132,"column":null}},"36":{"start":{"line":131,"column":2},"end":{"line":131,"column":null}},"37":{"start":{"line":137,"column":1},"end":{"line":139,"column":null}},"38":{"start":{"line":138,"column":2},"end":{"line":138,"column":null}},"39":{"start":{"line":141,"column":9},"end":{"line":146,"column":null}},"40":{"start":{"line":142,"column":2},"end":{"line":144,"column":null}},"41":{"start":{"line":143,"column":3},"end":{"line":143,"column":null}},"42":{"start":{"line":145,"column":2},"end":{"line":145,"column":null}},"43":{"start":{"line":153,"column":4},"end":{"line":160,"column":null}},"44":{"start":{"line":153,"column":13},"end":{"line":153,"column":35}},"45":{"start":{"line":154,"column":2},"end":{"line":159,"column":null}},"46":{"start":{"line":155,"column":3},"end":{"line":155,"column":null}},"47":{"start":{"line":157,"column":16},"end":{"line":157,"column":39}},"48":{"start":{"line":158,"column":3},"end":{"line":158,"column":null}},"49":{"start":{"line":168,"column":9},"end":{"line":185,"column":null}},"50":{"start":{"line":169,"column":20},"end":{"line":172,"column":null}},"51":{"start":{"line":174,"column":2},"end":{"line":183,"column":null}},"52":{"start":{"line":174,"column":15},"end":{"line":174,"column":16}},"53":{"start":{"line":175,"column":15},"end":{"line":175,"column":24}},"54":{"start":{"line":176,"column":3},"end":{"line":182,"column":null}},"55":{"start":{"line":177,"column":4},"end":{"line":177,"column":null}},"56":{"start":{"line":178,"column":4},"end":{"line":178,"column":null}},"57":{"start":{"line":180,"column":4},"end":{"line":180,"column":null}},"58":{"start":{"line":181,"column":4},"end":{"line":181,"column":null}},"59":{"start":{"line":184,"column":2},"end":{"line":184,"column":null}},"60":{"start":{"line":193,"column":9},"end":{"line":207,"column":null}},"61":{"start":{"line":194,"column":20},"end":{"line":194,"column":22}},"62":{"start":{"line":196,"column":8},"end":{"line":203,"column":null}},"63":{"start":{"line":196,"column":21},"end":{"line":196,"column":22}},"64":{"start":{"line":197,"column":24},"end":{"line":197,"column":33}},"65":{"start":{"line":198,"column":12},"end":{"line":202,"column":null}},"66":{"start":{"line":199,"column":16},"end":{"line":199,"column":null}},"67":{"start":{"line":201,"column":16},"end":{"line":201,"column":null}},"68":{"start":{"line":205,"column":2},"end":{"line":205,"column":null}},"69":{"start":{"line":209,"column":0},"end":{"line":209,"column":null}},"70":{"start":{"line":211,"column":0},"end":{"line":211,"column":null}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":7,"column":0},"end":{"line":7,"column":null}},"loc":{"start":{"line":7,"column":0},"end":{"line":209,"column":null}}},"1":{"name":"EventParser","decl":{"start":{"line":10,"column":1},"end":{"line":10,"column":14}},"loc":{"start":{"line":10,"column":34},"end":{"line":12,"column":2}}},"2":{"name":"(anonymous_2)","decl":{"start":{"line":17,"column":1},"end":{"line":17,"column":18}},"loc":{"start":{"line":17,"column":1},"end":{"line":19,"column":2}}},"3":{"name":"(anonymous_3)","decl":{"start":{"line":24,"column":1},"end":{"line":24,"column":18}},"loc":{"start":{"line":24,"column":1},"end":{"line":26,"column":2}}},"4":{"name":"(anonymous_4)","decl":{"start":{"line":31,"column":1},"end":{"line":31,"column":18}},"loc":{"start":{"line":31,"column":1},"end":{"line":33,"column":2}}},"5":{"name":"(anonymous_5)","decl":{"start":{"line":38,"column":1},"end":{"line":38,"column":18}},"loc":{"start":{"line":38,"column":1},"end":{"line":40,"column":2}}},"6":{"name":"(anonymous_6)","decl":{"start":{"line":45,"column":1},"end":{"line":45,"column":17}},"loc":{"start":{"line":45,"column":1},"end":{"line":47,"column":2}}},"7":{"name":"(anonymous_7)","decl":{"start":{"line":53,"column":1},"end":{"line":53,"column":19}},"loc":{"start":{"line":53,"column":31},"end":{"line":55,"column":2}}},"8":{"name":"(anonymous_8)","decl":{"start":{"line":60,"column":1},"end":{"line":60,"column":20}},"loc":{"start":{"line":60,"column":1},"end":{"line":62,"column":2}}},"9":{"name":"(anonymous_9)","decl":{"start":{"line":67,"column":1},"end":{"line":67,"column":6}},"loc":{"start":{"line":67,"column":1},"end":{"line":69,"column":2}}},"10":{"name":"(anonymous_10)","decl":{"start":{"line":74,"column":1},"end":{"line":74,"column":15}},"loc":{"start":{"line":74,"column":1},"end":{"line":76,"column":2}}},"11":{"name":"(anonymous_11)","decl":{"start":{"line":81,"column":1},"end":{"line":81,"column":14}},"loc":{"start":{"line":81,"column":1},"end":{"line":83,"column":2}}},"12":{"name":"(anonymous_12)","decl":{"start":{"line":88,"column":1},"end":{"line":88,"column":13}},"loc":{"start":{"line":88,"column":1},"end":{"line":90,"column":2}}},"13":{"name":"(anonymous_13)","decl":{"start":{"line":95,"column":1},"end":{"line":95,"column":16}},"loc":{"start":{"line":95,"column":1},"end":{"line":97,"column":2}}},"14":{"name":"(anonymous_14)","decl":{"start":{"line":102,"column":1},"end":{"line":102,"column":14}},"loc":{"start":{"line":102,"column":1},"end":{"line":104,"column":2}}},"15":{"name":"(anonymous_15)","decl":{"start":{"line":109,"column":1},"end":{"line":109,"column":11}},"loc":{"start":{"line":109,"column":1},"end":{"line":111,"column":2}}},"16":{"name":"(anonymous_16)","decl":{"start":{"line":116,"column":1},"end":{"line":116,"column":11}},"loc":{"start":{"line":116,"column":1},"end":{"line":118,"column":2}}},"17":{"name":"(anonymous_17)","decl":{"start":{"line":123,"column":1},"end":{"line":123,"column":13}},"loc":{"start":{"line":123,"column":1},"end":{"line":125,"column":2}}},"18":{"name":"(anonymous_18)","decl":{"start":{"line":130,"column":1},"end":{"line":130,"column":18}},"loc":{"start":{"line":130,"column":1},"end":{"line":132,"column":2}}},"19":{"name":"(anonymous_19)","decl":{"start":{"line":137,"column":1},"end":{"line":137,"column":22}},"loc":{"start":{"line":137,"column":1},"end":{"line":139,"column":2}}},"20":{"name":"(anonymous_20)","decl":{"start":{"line":141,"column":1},"end":{"line":141,"column":9}},"loc":{"start":{"line":141,"column":1},"end":{"line":146,"column":2}}},"21":{"name":"(anonymous_21)","decl":{"start":{"line":153,"column":4},"end":{"line":153,"column":11}},"loc":{"start":{"line":153,"column":4},"end":{"line":160,"column":2}}},"22":{"name":"(anonymous_22)","decl":{"start":{"line":168,"column":1},"end":{"line":168,"column":9}},"loc":{"start":{"line":168,"column":38},"end":{"line":185,"column":2}}},"23":{"name":"(anonymous_23)","decl":{"start":{"line":193,"column":1},"end":{"line":193,"column":9}},"loc":{"start":{"line":193,"column":62},"end":{"line":207,"column":2}}}},"branchMap":{"0":{"loc":{"start":{"line":96,"column":35},"end":{"line":96,"column":37}},"type":"cond-expr","locations":[{"start":{"line":96,"column":35},"end":{"line":96,"column":37}},{"start":{"line":96,"column":35},"end":{"line":96,"column":50}}]},"1":{"loc":{"start":{"line":96,"column":2},"end":{"line":96,"column":37}},"type":"binary-expr","locations":[{"start":{"line":96,"column":2},"end":{"line":96,"column":37}},{"start":{"line":96,"column":35},"end":{"line":96,"column":37}}]},"2":{"loc":{"start":{"line":103,"column":35},"end":{"line":103,"column":37}},"type":"cond-expr","locations":[{"start":{"line":103,"column":35},"end":{"line":103,"column":37}},{"start":{"line":103,"column":35},"end":{"line":103,"column":48}}]},"3":{"loc":{"start":{"line":103,"column":2},"end":{"line":103,"column":37}},"type":"binary-expr","locations":[{"start":{"line":103,"column":2},"end":{"line":103,"column":37}},{"start":{"line":103,"column":35},"end":{"line":103,"column":37}}]},"4":{"loc":{"start":{"line":142,"column":2},"end":{"line":144,"column":null}},"type":"if","locations":[{"start":{"line":142,"column":2},"end":{"line":144,"column":null}},{"start":{"line":142,"column":2},"end":{"line":144,"column":null}}]},"5":{"loc":{"start":{"line":142,"column":7},"end":{"line":142,"column":31}},"type":"binary-expr","locations":[{"start":{"line":142,"column":7},"end":{"line":142,"column":31}},{"start":{"line":142,"column":35},"end":{"line":142,"column":59}}]},"6":{"loc":{"start":{"line":154,"column":2},"end":{"line":159,"column":null}},"type":"if","locations":[{"start":{"line":154,"column":2},"end":{"line":159,"column":null}},{"start":{"line":154,"column":2},"end":{"line":159,"column":null}}]},"7":{"loc":{"start":{"line":176,"column":3},"end":{"line":182,"column":null}},"type":"if","locations":[{"start":{"line":176,"column":3},"end":{"line":182,"column":null}},{"start":{"line":176,"column":3},"end":{"line":182,"column":null}}]},"8":{"loc":{"start":{"line":176,"column":8},"end":{"line":176,"column":42}},"type":"binary-expr","locations":[{"start":{"line":176,"column":8},"end":{"line":176,"column":42}},{"start":{"line":176,"column":46},"end":{"line":176,"column":80}}]},"9":{"loc":{"start":{"line":198,"column":12},"end":{"line":202,"column":null}},"type":"if","locations":[{"start":{"line":198,"column":12},"end":{"line":202,"column":null}},{"start":{"line":198,"column":12},"end":{"line":202,"column":null}}]}},"s":{"0":1,"1":1,"2":22,"3":1,"4":4,"5":1,"6":5,"7":1,"8":1,"9":1,"10":3,"11":1,"12":14,"13":1,"14":3,"15":1,"16":1,"17":1,"18":1,"19":1,"20":1,"21":1,"22":1,"23":1,"24":1,"25":1,"26":2,"27":1,"28":2,"29":1,"30":1,"31":1,"32":1,"33":1,"34":1,"35":1,"36":1,"37":1,"38":1,"39":1,"40":4,"41":3,"42":1,"43":1,"44":22,"45":5,"46":1,"47":4,"48":4,"49":1,"50":1,"51":1,"52":1,"53":2,"54":2,"55":1,"56":1,"57":1,"58":1,"59":1,"60":1,"61":4,"62":4,"63":4,"64":10,"65":10,"66":6,"67":4,"68":4,"69":1,"70":1},"f":{"0":1,"1":22,"2":4,"3":5,"4":1,"5":3,"6":14,"7":3,"8":1,"9":1,"10":1,"11":1,"12":1,"13":2,"14":2,"15":1,"16":1,"17":1,"18":1,"19":1,"20":4,"21":5,"22":1,"23":4},"b":{"0":[1,1],"1":[2,2],"2":[1,1],"3":[2,2],"4":[3,1],"5":[4,2],"6":[1,4],"7":[1,1],"8":[2,1],"9":[6,4]}} 3 | ,"/Users/bostjan/Projects/GraphQL/HasuraParser/src/types.ts": {"path":"/Users/bostjan/Projects/GraphQL/HasuraParser/src/types.ts","statementMap":{"0":{"start":{"line":58,"column":0},"end":{"line":58,"column":null}},"1":{"start":{"line":59,"column":1},"end":{"line":59,"column":null}},"2":{"start":{"line":60,"column":1},"end":{"line":60,"column":null}},"3":{"start":{"line":61,"column":1},"end":{"line":61,"column":null}},"4":{"start":{"line":62,"column":1},"end":{"line":62,"column":null}},"5":{"start":{"line":84,"column":1},"end":{"line":84,"column":25}},"6":{"start":{"line":65,"column":0},"end":{"line":65,"column":null}},"7":{"start":{"line":66,"column":1},"end":{"line":66,"column":null}},"8":{"start":{"line":67,"column":1},"end":{"line":67,"column":null}},"9":{"start":{"line":78,"column":1},"end":{"line":78,"column":19}},"10":{"start":{"line":70,"column":0},"end":{"line":70,"column":null}},"11":{"start":{"line":71,"column":1},"end":{"line":71,"column":null}},"12":{"start":{"line":72,"column":1},"end":{"line":72,"column":null}},"13":{"start":{"line":76,"column":1},"end":{"line":76,"column":15}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":58,"column":0},"end":{"line":58,"column":5}},"loc":{"start":{"line":58,"column":29},"end":{"line":63,"column":1}}},"1":{"name":"(anonymous_1)","decl":{"start":{"line":65,"column":0},"end":{"line":65,"column":5}},"loc":{"start":{"line":65,"column":23},"end":{"line":68,"column":1}}},"2":{"name":"(anonymous_2)","decl":{"start":{"line":70,"column":0},"end":{"line":70,"column":5}},"loc":{"start":{"line":70,"column":19},"end":{"line":73,"column":1}}}},"branchMap":{"0":{"loc":{"start":{"line":58,"column":5},"end":{"line":58,"column":29}},"type":"binary-expr","locations":[{"start":{"line":58,"column":5},"end":{"line":58,"column":29}},{"start":{"line":58,"column":5},"end":{"line":58,"column":null}}]},"1":{"loc":{"start":{"line":65,"column":5},"end":{"line":65,"column":23}},"type":"binary-expr","locations":[{"start":{"line":65,"column":5},"end":{"line":65,"column":23}},{"start":{"line":65,"column":5},"end":{"line":65,"column":null}}]},"2":{"loc":{"start":{"line":70,"column":5},"end":{"line":70,"column":19}},"type":"binary-expr","locations":[{"start":{"line":70,"column":5},"end":{"line":70,"column":19}},{"start":{"line":70,"column":5},"end":{"line":70,"column":null}}]}},"s":{"0":1,"1":1,"2":1,"3":1,"4":1,"5":1,"6":1,"7":1,"8":1,"9":1,"10":1,"11":1,"12":1,"13":1},"f":{"0":1,"1":1,"2":1},"b":{"0":[1,1],"1":[1,1],"2":[1,1]}} 4 | } 5 | -------------------------------------------------------------------------------- /coverage/lcov-report/action.ts.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Code coverage report for action.ts 7 | 8 | 9 | 10 | 11 | 12 | 17 | 18 | 19 | 20 |
21 |
22 |

All files action.ts

23 |
24 | 25 |
26 | 100% 27 | Statements 28 | 27/27 29 |
30 | 31 | 32 |
33 | 100% 34 | Branches 35 | 6/6 36 |
37 | 38 | 39 |
40 | 100% 41 | Functions 42 | 7/7 43 |
44 | 45 | 46 |
47 | 100% 48 | Lines 49 | 25/25 50 |
51 | 52 | 53 |
54 |

55 | Press n or j to go to the next uncovered block, b, p or k for the previous block. 56 |

57 |
58 |
59 |

 60 | 
1 61 | 2 62 | 3 63 | 4 64 | 5 65 | 6 66 | 7 67 | 8 68 | 9 69 | 10 70 | 11 71 | 12 72 | 13 73 | 14 74 | 15 75 | 16 76 | 17 77 | 18 78 | 19 79 | 20 80 | 21 81 | 22 82 | 23 83 | 24 84 | 25 85 | 26 86 | 27 87 | 28 88 | 29 89 | 30 90 | 31 91 | 32 92 | 33 93 | 34 94 | 35 95 | 36 96 | 37 97 | 38 98 | 39 99 | 40 100 | 41 101 | 42 102 | 43 103 | 44 104 | 45 105 | 46 106 | 47 107 | 48 108 | 49 109 | 50 110 | 51 111 | 52 112 | 53 113 | 54 114 | 55 115 | 56 116 | 57 117 | 58 118 | 59 119 | 60 120 | 61 121 | 62 122 | 63 123 | 64 124 | 65 125 | 66 126 | 67 127 | 68 128 | 69 129 | 70 130 | 71 131 | 72 132 | 73 133 | 74 134 | 75  135 |   136 |   137 |   138 | 1x 139 |   140 |   141 |   142 | 7x 143 |   144 |   145 |   146 |   147 |   148 |   149 | 1x 150 | 2x 151 |   152 |   153 |   154 |   155 |   156 | 1x 157 | 1x 158 |   159 |   160 |   161 |   162 |   163 | 1x 164 | 1x 165 |   166 |   167 |   168 |   169 |   170 |   171 |   172 | 10x 173 |   174 |   175 | 2x 176 |   177 |   178 | 2x 179 | 1x 180 |   181 | 1x 182 |   183 |   184 | 2x 185 | 6x 186 | 6x 187 | 4x 188 |   189 | 2x 190 |   191 |   192 |   193 | 2x 194 |   195 |   196 |   197 |   198 |   199 | 1x 200 | 2x 201 | 1x 202 |   203 | 1x 204 |   205 |   206 | 1x 207 |   208 | 1x
import {
209 |     HasuraAction
210 | } from './types'
211 |  
212 | class ActionParser {
213 | 	private payload: HasuraAction
214 |  
215 | 	constructor( payload: HasuraAction ) {
216 | 		this.payload = payload
217 |     }
218 |     
219 |     /**
220 |      * Returns session variable by ID.
221 |      * @param id    ID of session variable (e.g. x-hasura-user-role).
222 |      */
223 | 	getSessionVariable( id: string ): string {
224 | 		return this.payload.session_variables[ id ]
225 | 	}
226 |  
227 |     /**
228 |      * Returns all session variables.
229 |      */
230 |     getSessionVariables(): any {
231 | 		return this.payload.session_variables
232 |     }
233 |     
234 |     /**
235 |      * Returns action name.
236 |      */
237 |     getActionName(): string {
238 |         return this.payload.action.name
239 |     }
240 |  
241 |     /**
242 |      * Gets data from action for provided keys.
243 |      * 
244 |      * @param keys  Keys to fetch.
245 |      */
246 |     getData( ...keys: Array<string> ): any {
247 |         let payload;
248 |  
249 |         const data: any = {}
250 |         
251 |         // Some people prefer to do input on mutations and other operations
252 |         if ( this.payload.input.input ) {
253 |             payload = this.payload.input.input
254 |         } else {
255 |             payload = this.payload.input
256 |         }
257 |  
258 |         for ( let i = 0; i < keys.length; i++ ) {
259 |             const key = keys[ i ]
260 |             if ( payload[ key ] ) {
261 |                 data[ key ] = payload[ key ]
262 |             } else {
263 |                 data[ key ] = null
264 |             }
265 |         }
266 |  
267 |         return data
268 |     }
269 |  
270 |     /**
271 |      * Returns raw data from payload (not fetching by keys we need.)
272 |      */
273 |     getRawData(): any {
274 |         if ( this.payload.input.input ) {
275 |             return this.payload.input.input
276 |         }
277 |         return this.payload.input
278 |     }
279 |  
280 | }
281 |  
282 | export default ActionParser
283 | 284 |
285 |
286 | 291 | 292 | 293 | 298 | 299 | 300 | 301 | 302 | -------------------------------------------------------------------------------- /coverage/lcov-report/base.css: -------------------------------------------------------------------------------- 1 | body, html { 2 | margin:0; padding: 0; 3 | height: 100%; 4 | } 5 | body { 6 | font-family: Helvetica Neue, Helvetica, Arial; 7 | font-size: 14px; 8 | color:#333; 9 | } 10 | .small { font-size: 12px; } 11 | *, *:after, *:before { 12 | -webkit-box-sizing:border-box; 13 | -moz-box-sizing:border-box; 14 | box-sizing:border-box; 15 | } 16 | h1 { font-size: 20px; margin: 0;} 17 | h2 { font-size: 14px; } 18 | pre { 19 | font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace; 20 | margin: 0; 21 | padding: 0; 22 | -moz-tab-size: 2; 23 | -o-tab-size: 2; 24 | tab-size: 2; 25 | } 26 | a { color:#0074D9; text-decoration:none; } 27 | a:hover { text-decoration:underline; } 28 | .strong { font-weight: bold; } 29 | .space-top1 { padding: 10px 0 0 0; } 30 | .pad2y { padding: 20px 0; } 31 | .pad1y { padding: 10px 0; } 32 | .pad2x { padding: 0 20px; } 33 | .pad2 { padding: 20px; } 34 | .pad1 { padding: 10px; } 35 | .space-left2 { padding-left:55px; } 36 | .space-right2 { padding-right:20px; } 37 | .center { text-align:center; } 38 | .clearfix { display:block; } 39 | .clearfix:after { 40 | content:''; 41 | display:block; 42 | height:0; 43 | clear:both; 44 | visibility:hidden; 45 | } 46 | .fl { float: left; } 47 | @media only screen and (max-width:640px) { 48 | .col3 { width:100%; max-width:100%; } 49 | .hide-mobile { display:none!important; } 50 | } 51 | 52 | .quiet { 53 | color: #7f7f7f; 54 | color: rgba(0,0,0,0.5); 55 | } 56 | .quiet a { opacity: 0.7; } 57 | 58 | .fraction { 59 | font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; 60 | font-size: 10px; 61 | color: #555; 62 | background: #E8E8E8; 63 | padding: 4px 5px; 64 | border-radius: 3px; 65 | vertical-align: middle; 66 | } 67 | 68 | div.path a:link, div.path a:visited { color: #333; } 69 | table.coverage { 70 | border-collapse: collapse; 71 | margin: 10px 0 0 0; 72 | padding: 0; 73 | } 74 | 75 | table.coverage td { 76 | margin: 0; 77 | padding: 0; 78 | vertical-align: top; 79 | } 80 | table.coverage td.line-count { 81 | text-align: right; 82 | padding: 0 5px 0 20px; 83 | } 84 | table.coverage td.line-coverage { 85 | text-align: right; 86 | padding-right: 10px; 87 | min-width:20px; 88 | } 89 | 90 | table.coverage td span.cline-any { 91 | display: inline-block; 92 | padding: 0 5px; 93 | width: 100%; 94 | } 95 | .missing-if-branch { 96 | display: inline-block; 97 | margin-right: 5px; 98 | border-radius: 3px; 99 | position: relative; 100 | padding: 0 4px; 101 | background: #333; 102 | color: yellow; 103 | } 104 | 105 | .skip-if-branch { 106 | display: none; 107 | margin-right: 10px; 108 | position: relative; 109 | padding: 0 4px; 110 | background: #ccc; 111 | color: white; 112 | } 113 | .missing-if-branch .typ, .skip-if-branch .typ { 114 | color: inherit !important; 115 | } 116 | .coverage-summary { 117 | border-collapse: collapse; 118 | width: 100%; 119 | } 120 | .coverage-summary tr { border-bottom: 1px solid #bbb; } 121 | .keyline-all { border: 1px solid #ddd; } 122 | .coverage-summary td, .coverage-summary th { padding: 10px; } 123 | .coverage-summary tbody { border: 1px solid #bbb; } 124 | .coverage-summary td { border-right: 1px solid #bbb; } 125 | .coverage-summary td:last-child { border-right: none; } 126 | .coverage-summary th { 127 | text-align: left; 128 | font-weight: normal; 129 | white-space: nowrap; 130 | } 131 | .coverage-summary th.file { border-right: none !important; } 132 | .coverage-summary th.pct { } 133 | .coverage-summary th.pic, 134 | .coverage-summary th.abs, 135 | .coverage-summary td.pct, 136 | .coverage-summary td.abs { text-align: right; } 137 | .coverage-summary td.file { white-space: nowrap; } 138 | .coverage-summary td.pic { min-width: 120px !important; } 139 | .coverage-summary tfoot td { } 140 | 141 | .coverage-summary .sorter { 142 | height: 10px; 143 | width: 7px; 144 | display: inline-block; 145 | margin-left: 0.5em; 146 | background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent; 147 | } 148 | .coverage-summary .sorted .sorter { 149 | background-position: 0 -20px; 150 | } 151 | .coverage-summary .sorted-desc .sorter { 152 | background-position: 0 -10px; 153 | } 154 | .status-line { height: 10px; } 155 | /* yellow */ 156 | .cbranch-no { background: yellow !important; color: #111; } 157 | /* dark red */ 158 | .red.solid, .status-line.low, .low .cover-fill { background:#C21F39 } 159 | .low .chart { border:1px solid #C21F39 } 160 | .highlighted, 161 | .highlighted .cstat-no, .highlighted .fstat-no, .highlighted .cbranch-no{ 162 | background: #C21F39 !important; 163 | } 164 | /* medium red */ 165 | .cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE } 166 | /* light red */ 167 | .low, .cline-no { background:#FCE1E5 } 168 | /* light green */ 169 | .high, .cline-yes { background:rgb(230,245,208) } 170 | /* medium green */ 171 | .cstat-yes { background:rgb(161,215,106) } 172 | /* dark green */ 173 | .status-line.high, .high .cover-fill { background:rgb(77,146,33) } 174 | .high .chart { border:1px solid rgb(77,146,33) } 175 | /* dark yellow (gold) */ 176 | .status-line.medium, .medium .cover-fill { background: #f9cd0b; } 177 | .medium .chart { border:1px solid #f9cd0b; } 178 | /* light yellow */ 179 | .medium { background: #fff4c2; } 180 | 181 | .cstat-skip { background: #ddd; color: #111; } 182 | .fstat-skip { background: #ddd; color: #111 !important; } 183 | .cbranch-skip { background: #ddd !important; color: #111; } 184 | 185 | span.cline-neutral { background: #eaeaea; } 186 | 187 | .coverage-summary td.empty { 188 | opacity: .5; 189 | padding-top: 4px; 190 | padding-bottom: 4px; 191 | line-height: 1; 192 | color: #888; 193 | } 194 | 195 | .cover-fill, .cover-empty { 196 | display:inline-block; 197 | height: 12px; 198 | } 199 | .chart { 200 | line-height: 0; 201 | } 202 | .cover-empty { 203 | background: white; 204 | } 205 | .cover-full { 206 | border-right: none !important; 207 | } 208 | pre.prettyprint { 209 | border: none !important; 210 | padding: 0 !important; 211 | margin: 0 !important; 212 | } 213 | .com { color: #999 !important; } 214 | .ignore-none { color: #999; font-weight: normal; } 215 | 216 | .wrapper { 217 | min-height: 100%; 218 | height: auto !important; 219 | height: 100%; 220 | margin: 0 auto -48px; 221 | } 222 | .footer, .push { 223 | height: 48px; 224 | } 225 | -------------------------------------------------------------------------------- /coverage/lcov-report/block-navigation.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | var jumpToCode = (function init() { 3 | // Classes of code we would like to highlight in the file view 4 | var missingCoverageClasses = ['.cbranch-no', '.cstat-no', '.fstat-no']; 5 | 6 | // Elements to highlight in the file listing view 7 | var fileListingElements = ['td.pct.low']; 8 | 9 | // We don't want to select elements that are direct descendants of another match 10 | var notSelector = ':not(' + missingCoverageClasses.join('):not(') + ') > '; // becomes `:not(a):not(b) > ` 11 | 12 | // Selecter that finds elements on the page to which we can jump 13 | var selector = 14 | fileListingElements.join(', ') + 15 | ', ' + 16 | notSelector + 17 | missingCoverageClasses.join(', ' + notSelector); // becomes `:not(a):not(b) > a, :not(a):not(b) > b` 18 | 19 | // The NodeList of matching elements 20 | var missingCoverageElements = document.querySelectorAll(selector); 21 | 22 | var currentIndex; 23 | 24 | function toggleClass(index) { 25 | missingCoverageElements 26 | .item(currentIndex) 27 | .classList.remove('highlighted'); 28 | missingCoverageElements.item(index).classList.add('highlighted'); 29 | } 30 | 31 | function makeCurrent(index) { 32 | toggleClass(index); 33 | currentIndex = index; 34 | missingCoverageElements.item(index).scrollIntoView({ 35 | behavior: 'smooth', 36 | block: 'center', 37 | inline: 'center' 38 | }); 39 | } 40 | 41 | function goToPrevious() { 42 | var nextIndex = 0; 43 | if (typeof currentIndex !== 'number' || currentIndex === 0) { 44 | nextIndex = missingCoverageElements.length - 1; 45 | } else if (missingCoverageElements.length > 1) { 46 | nextIndex = currentIndex - 1; 47 | } 48 | 49 | makeCurrent(nextIndex); 50 | } 51 | 52 | function goToNext() { 53 | var nextIndex = 0; 54 | 55 | if ( 56 | typeof currentIndex === 'number' && 57 | currentIndex < missingCoverageElements.length - 1 58 | ) { 59 | nextIndex = currentIndex + 1; 60 | } 61 | 62 | makeCurrent(nextIndex); 63 | } 64 | 65 | return function jump(event) { 66 | switch (event.which) { 67 | case 78: // n 68 | case 74: // j 69 | goToNext(); 70 | break; 71 | case 66: // b 72 | case 75: // k 73 | case 80: // p 74 | goToPrevious(); 75 | break; 76 | } 77 | }; 78 | })(); 79 | window.addEventListener('keydown', jumpToCode); 80 | -------------------------------------------------------------------------------- /coverage/lcov-report/event.ts.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Code coverage report for event.ts 7 | 8 | 9 | 10 | 11 | 12 | 17 | 18 | 19 | 20 |
21 |
22 |

All files event.ts

23 |
24 | 25 |
26 | 100% 27 | Statements 28 | 71/71 29 |
30 | 31 | 32 |
33 | 100% 34 | Branches 35 | 20/20 36 |
37 | 38 | 39 |
40 | 100% 41 | Functions 42 | 24/24 43 |
44 | 45 | 46 |
47 | 100% 48 | Lines 49 | 68/68 50 |
51 | 52 | 53 |
54 |

55 | Press n or j to go to the next uncovered block, b, p or k for the previous block. 56 |

57 |
58 |
59 |

 60 | 
1 61 | 2 62 | 3 63 | 4 64 | 5 65 | 6 66 | 7 67 | 8 68 | 9 69 | 10 70 | 11 71 | 12 72 | 13 73 | 14 74 | 15 75 | 16 76 | 17 77 | 18 78 | 19 79 | 20 80 | 21 81 | 22 82 | 23 83 | 24 84 | 25 85 | 26 86 | 27 87 | 28 88 | 29 89 | 30 90 | 31 91 | 32 92 | 33 93 | 34 94 | 35 95 | 36 96 | 37 97 | 38 98 | 39 99 | 40 100 | 41 101 | 42 102 | 43 103 | 44 104 | 45 105 | 46 106 | 47 107 | 48 108 | 49 109 | 50 110 | 51 111 | 52 112 | 53 113 | 54 114 | 55 115 | 56 116 | 57 117 | 58 118 | 59 119 | 60 120 | 61 121 | 62 122 | 63 123 | 64 124 | 65 125 | 66 126 | 67 127 | 68 128 | 69 129 | 70 130 | 71 131 | 72 132 | 73 133 | 74 134 | 75 135 | 76 136 | 77 137 | 78 138 | 79 139 | 80 140 | 81 141 | 82 142 | 83 143 | 84 144 | 85 145 | 86 146 | 87 147 | 88 148 | 89 149 | 90 150 | 91 151 | 92 152 | 93 153 | 94 154 | 95 155 | 96 156 | 97 157 | 98 158 | 99 159 | 100 160 | 101 161 | 102 162 | 103 163 | 104 164 | 105 165 | 106 166 | 107 167 | 108 168 | 109 169 | 110 170 | 111 171 | 112 172 | 113 173 | 114 174 | 115 175 | 116 176 | 117 177 | 118 178 | 119 179 | 120 180 | 121 181 | 122 182 | 123 183 | 124 184 | 125 185 | 126 186 | 127 187 | 128 188 | 129 189 | 130 190 | 131 191 | 132 192 | 133 193 | 134 194 | 135 195 | 136 196 | 137 197 | 138 198 | 139 199 | 140 200 | 141 201 | 142 202 | 143 203 | 144 204 | 145 205 | 146 206 | 147 207 | 148 208 | 149 209 | 150 210 | 151 211 | 152 212 | 153 213 | 154 214 | 155 215 | 156 216 | 157 217 | 158 218 | 159 219 | 160 220 | 161 221 | 162 222 | 163 223 | 164 224 | 165 225 | 166 226 | 167 227 | 168 228 | 169 229 | 170 230 | 171 231 | 172 232 | 173 233 | 174 234 | 175 235 | 176 236 | 177 237 | 178 238 | 179 239 | 180 240 | 181 241 | 182 242 | 183 243 | 184 244 | 185 245 | 186 246 | 187 247 | 188 248 | 189 249 | 190 250 | 191 251 | 192 252 | 193 253 | 194 254 | 195 255 | 196 256 | 197 257 | 198 258 | 199 259 | 200 260 | 201 261 | 202 262 | 203 263 | 204 264 | 205 265 | 206 266 | 207 267 | 208 268 | 209 269 | 210 270 | 2111x 271 |   272 |   273 |   274 |   275 |   276 | 1x 277 |   278 |   279 |   280 | 22x 281 |   282 |   283 |   284 |   285 |   286 | 1x 287 | 4x 288 |   289 |   290 |   291 |   292 |   293 | 1x 294 | 5x 295 |   296 |   297 |   298 |   299 |   300 | 1x 301 | 1x 302 |   303 |   304 |   305 |   306 |   307 | 1x 308 | 3x 309 |   310 |   311 |   312 |   313 |   314 | 1x 315 | 14x 316 |   317 |   318 |   319 |   320 |   321 |   322 | 1x 323 | 3x 324 |   325 |   326 |   327 |   328 |   329 | 1x 330 | 1x 331 |   332 |   333 |   334 |   335 |   336 | 1x 337 | 1x 338 |   339 |   340 |   341 |   342 |   343 | 1x 344 | 1x 345 |   346 |   347 |   348 |   349 |   350 | 1x 351 | 1x 352 |   353 |   354 |   355 |   356 |   357 | 1x 358 | 1x 359 |   360 |   361 |   362 |   363 |   364 | 1x 365 | 2x 366 |   367 |   368 |   369 |   370 |   371 | 1x 372 | 2x 373 |   374 |   375 |   376 |   377 |   378 | 1x 379 | 1x 380 |   381 |   382 |   383 |   384 |   385 | 1x 386 | 1x 387 |   388 |   389 |   390 |   391 |   392 | 1x 393 | 1x 394 |   395 |   396 |   397 |   398 |   399 | 1x 400 | 1x 401 |   402 |   403 |   404 |   405 |   406 | 1x 407 | 1x 408 |   409 |   410 | 1x 411 | 4x 412 | 3x 413 |   414 | 1x 415 |   416 |   417 |   418 |   419 |   420 |   421 |   422 | 22x 423 | 5x 424 | 1x 425 |   426 | 4x 427 | 4x 428 |   429 |   430 |   431 |   432 |   433 |   434 |   435 |   436 |   437 | 1x 438 | 1x 439 |   440 |   441 |   442 |   443 | 1x 444 | 2x 445 | 2x 446 | 1x 447 | 1x 448 |   449 | 1x 450 | 1x 451 |   452 |   453 | 1x 454 |   455 |   456 |   457 |   458 |   459 |   460 |   461 |   462 | 1x 463 | 4x 464 |   465 | 4x 466 | 10x 467 | 10x 468 | 6x 469 |   470 | 4x 471 |   472 |   473 |   474 | 4x 475 |   476 |   477 |   478 | 1x 479 |   480 | 1x
import {
481 | 	HasuraEvent,
482 | 	HasuraEventOperationType,
483 | 	HasuraDataType
484 | } from './types'
485 |  
486 | class EventParser {
487 | 	private payload: HasuraEvent
488 |  
489 | 	constructor( payload: HasuraEvent ) {
490 | 		this.payload = payload
491 | 	}
492 |  
493 | 	/**
494 | 	 * Returns if operation is an INSERT.
495 | 	 */
496 | 	isInsertOperation(): boolean {
497 | 		return this.getOperationType() === HasuraEventOperationType.INSERT
498 | 	}
499 |  
500 | 	/**
501 | 	 * Checks if operation is an UPDATE.
502 | 	 */
503 | 	isUpdateOperation(): boolean {
504 | 		return this.getOperationType() === HasuraEventOperationType.UPDATE
505 | 	}
506 |  
507 | 	/**
508 | 	 * Checks if operation is a DELETE.
509 | 	 */
510 | 	isDeleteOperation(): boolean {
511 | 		return this.getOperationType() === HasuraEventOperationType.DELETE
512 | 	}
513 |  
514 | 	/**
515 | 	 * Checks if operation is MANUAL.
516 | 	 */
517 | 	isManualOperation(): boolean {
518 | 		return this.getOperationType() === HasuraEventOperationType.MANUAL
519 | 	}
520 |  
521 | 	/**
522 | 	 * Returns operation type.
523 | 	 */
524 | 	getOperationType(): string {
525 | 		return this.payload.event.op
526 | 	}
527 |  
528 | 	/**
529 | 	 * Returns session variable by provided ID (e.g. x-hasura-user-role).
530 | 	 * @param id  ID of session variable.
531 | 	 */
532 | 	getSessionVariable( id: string ): string {
533 | 		return this.payload.event.session_variables[ id ]
534 | 	}
535 |  
536 | 	/**
537 | 	 * Returns all session variables.
538 | 	 */
539 | 	getSessionVariables(): any {
540 | 		return this.payload.event.session_variables
541 | 	}
542 |  
543 | 	/**
544 | 	 * Returns ID of payload.
545 | 	 */
546 | 	getID(): string {
547 | 		return this.payload.id
548 | 	}
549 |  
550 | 	/**
551 | 	 * Returns trigger name (set in Hasura Console).
552 | 	 */
553 | 	getTriggerName(): string {
554 | 		return this.payload.trigger.name
555 | 	}
556 |  
557 | 	/**
558 | 	 * Gets schema name that the event affected.
559 | 	 */
560 | 	getSchemaName(): string {
561 | 		return this.payload.table.schema
562 | 	}
563 |  
564 | 	/**
565 | 	 * Gets table name that the event affected.
566 | 	 */
567 | 	getTableName(): string {
568 | 		return this.payload.table.name
569 | 	}
570 |  
571 | 	/**
572 | 	 * Returns current retry of the event (if it is set in Hasura Console).
573 | 	 */
574 | 	getCurrentRetry(): number | undefined {
575 | 		return this.payload.delivery_info?.current_retry
576 | 	}
577 |  
578 | 	/**
579 | 	 * Returns max retries for current event.
580 | 	 */
581 | 	getMaxRetries(): number | undefined {
582 | 		return this.payload.delivery_info?.max_retries
583 | 	}
584 |  
585 | 	/**
586 | 	 * Returns raw data (old - in UPDATE, DELETE and MANUAL events).
587 | 	 */
588 | 	getOldData(): any {
589 | 		return this.payload.event.data.old
590 | 	}
591 |  
592 | 	/**
593 | 	 * Returns raw data (new - in INSERT, UPDATE events).
594 | 	 */
595 | 	getNewData(): any {
596 | 		return this.payload.event.data.new
597 | 	}
598 |  
599 | 	/**
600 | 	 * Returns timestamp of event.
601 | 	 */
602 | 	getTimestamp() {
603 | 		return this.payload.created_at
604 | 	}
605 |  
606 | 	/**
607 | 	 * Returns trace data - context ID.
608 | 	 */
609 | 	getTraceContextID(): number {
610 | 		return this.payload.trace_context.trace_id
611 | 	}
612 |  
613 | 	/**
614 | 	 * Returns trace data - span context ID.
615 | 	 */
616 | 	getTraceContextSpanID(): number {
617 | 		return this.payload.trace_context.span_id
618 | 	}
619 |  
620 | 	private getDataFetchType(): HasuraDataType {
621 | 		if ( this.isInsertOperation() || this.isManualOperation() ) {
622 | 			return HasuraDataType.NEW
623 | 		}
624 | 		return HasuraDataType.OLD
625 | 	}
626 |  
627 | 	/**
628 | 	 * Fetches data that was sent by Hasura event by the keys provided.
629 | 	 *
630 | 	 * @param keys	Data to fetch.
631 | 	 */
632 |     getData( ...keys: Array<string> ) {
633 | 		if ( this.isUpdateOperation() ) {
634 | 			return this.getUData( keys )
635 | 		} else {
636 | 			const type = this.getDataFetchType()
637 | 			return this.getIDMData( keys, type )
638 | 		}
639 | 	}
640 |  
641 | 	/**
642 | 	 * Fetches update data by keys. If a key does not exist in both new
643 | 	 * and old the value is set to null and an info message is triggered.
644 | 	 * 
645 | 	 * @param keys	Keys to fetch.
646 | 	 */
647 | 	private getUData( keys: Array<string> ) {
648 | 		const data: any = {
649 | 			old: {},
650 | 			new: {}
651 | 		}
652 |  
653 | 		for( let i = 0; i < keys.length; i++ ) {
654 | 			const key = keys[ i ]
655 | 			if ( this.payload.event.data.old[ key ] && this.payload.event.data.new[ key ] ) {
656 | 				data.old[ key ] = this.payload.event.data.old[ key ]
657 | 				data.new[ key ] = this.payload.event.data.new[ key ]
658 | 			} else {
659 | 				data.old[ key ] = null
660 | 				data.new[ key ] = null
661 | 			}
662 | 		}
663 | 		return data
664 | 	}
665 | 	
666 | 	/**
667 | 	 * Fetches data for an INSERT, DELETE or MANUAL operation.
668 | 	 * 
669 | 	 * @param keys	Keys to fetch.
670 | 	 * @param type 	Type of operation.
671 | 	 */
672 | 	private getIDMData( keys: Array<string>, type: HasuraDataType ): any {
673 | 		const data: any = {}
674 |  
675 |         for( let i = 0; i < keys.length; i++ ) {
676 |             const key = keys[ i ]
677 |             if ( this.payload.event.data[ type ][ key ] ) {
678 |                 data[ key ] = this.payload.event.data[ type ][ key ]
679 |             } else {
680 |                 data[ key ] = null
681 |             }
682 | 		}
683 | 		
684 | 		return data
685 |  
686 | 	}
687 |  
688 | }
689 |  
690 | export default EventParser
691 | 692 |
693 |
694 | 699 | 700 | 701 | 706 | 707 | 708 | 709 | 710 | -------------------------------------------------------------------------------- /coverage/lcov-report/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snotra-org/hasura-parser/a17e821f278691bd69d3465c866888af05a361d2/coverage/lcov-report/favicon.png -------------------------------------------------------------------------------- /coverage/lcov-report/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Code coverage report for All files 7 | 8 | 9 | 10 | 11 | 12 | 17 | 18 | 19 | 20 |
21 |
22 |

All files

23 |
24 | 25 |
26 | 100% 27 | Statements 28 | 112/112 29 |
30 | 31 | 32 |
33 | 100% 34 | Branches 35 | 32/32 36 |
37 | 38 | 39 |
40 | 100% 41 | Functions 42 | 34/34 43 |
44 | 45 | 46 |
47 | 100% 48 | Lines 49 | 107/107 50 |
51 | 52 | 53 |
54 |

55 | Press n or j to go to the next uncovered block, b, p or k for the previous block. 56 |

57 |
58 |
59 |
60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 |
FileStatementsBranchesFunctionsLines
action.ts 78 |
79 |
100%27/27100%6/6100%7/7100%25/25
event.ts 93 |
94 |
100%71/71100%20/20100%24/24100%68/68
types.ts 108 |
109 |
100%14/14100%6/6100%3/3100%14/14
122 |
123 |
124 |
125 | 130 | 131 | 132 | 137 | 138 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /coverage/lcov-report/prettify.css: -------------------------------------------------------------------------------- 1 | .pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} 2 | -------------------------------------------------------------------------------- /coverage/lcov-report/prettify.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | window.PR_SHOULD_USE_CONTINUATION=true;(function(){var h=["break,continue,do,else,for,if,return,while"];var u=[h,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"];var p=[u,"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"];var l=[p,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"];var x=[p,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"];var R=[x,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"];var r="all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes";var w=[p,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"];var s="caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END";var I=[h,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"];var f=[h,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"];var H=[h,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"];var A=[l,R,w,s+I,f,H];var e=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/;var C="str";var z="kwd";var j="com";var O="typ";var G="lit";var L="pun";var F="pln";var m="tag";var E="dec";var J="src";var P="atn";var n="atv";var N="nocode";var M="(?:^^\\.?|[+-]|\\!|\\!=|\\!==|\\#|\\%|\\%=|&|&&|&&=|&=|\\(|\\*|\\*=|\\+=|\\,|\\-=|\\->|\\/|\\/=|:|::|\\;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\@|\\[|\\^|\\^=|\\^\\^|\\^\\^=|\\{|\\||\\|=|\\|\\||\\|\\|=|\\~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*";function k(Z){var ad=0;var S=false;var ac=false;for(var V=0,U=Z.length;V122)){if(!(al<65||ag>90)){af.push([Math.max(65,ag)|32,Math.min(al,90)|32])}if(!(al<97||ag>122)){af.push([Math.max(97,ag)&~32,Math.min(al,122)&~32])}}}}af.sort(function(av,au){return(av[0]-au[0])||(au[1]-av[1])});var ai=[];var ap=[NaN,NaN];for(var ar=0;arat[0]){if(at[1]+1>at[0]){an.push("-")}an.push(T(at[1]))}}an.push("]");return an.join("")}function W(al){var aj=al.source.match(new RegExp("(?:\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]|\\\\u[A-Fa-f0-9]{4}|\\\\x[A-Fa-f0-9]{2}|\\\\[0-9]+|\\\\[^ux0-9]|\\(\\?[:!=]|[\\(\\)\\^]|[^\\x5B\\x5C\\(\\)\\^]+)","g"));var ah=aj.length;var an=[];for(var ak=0,am=0;ak=2&&ai==="["){aj[ak]=X(ag)}else{if(ai!=="\\"){aj[ak]=ag.replace(/[a-zA-Z]/g,function(ao){var ap=ao.charCodeAt(0);return"["+String.fromCharCode(ap&~32,ap|32)+"]"})}}}}return aj.join("")}var aa=[];for(var V=0,U=Z.length;V=0;){S[ac.charAt(ae)]=Y}}var af=Y[1];var aa=""+af;if(!ag.hasOwnProperty(aa)){ah.push(af);ag[aa]=null}}ah.push(/[\0-\uffff]/);V=k(ah)})();var X=T.length;var W=function(ah){var Z=ah.sourceCode,Y=ah.basePos;var ad=[Y,F];var af=0;var an=Z.match(V)||[];var aj={};for(var ae=0,aq=an.length;ae=5&&"lang-"===ap.substring(0,5);if(am&&!(ai&&typeof ai[1]==="string")){am=false;ap=J}if(!am){aj[ag]=ap}}var ab=af;af+=ag.length;if(!am){ad.push(Y+ab,ap)}else{var al=ai[1];var ak=ag.indexOf(al);var ac=ak+al.length;if(ai[2]){ac=ag.length-ai[2].length;ak=ac-al.length}var ar=ap.substring(5);B(Y+ab,ag.substring(0,ak),W,ad);B(Y+ab+ak,al,q(ar,al),ad);B(Y+ab+ac,ag.substring(ac),W,ad)}}ah.decorations=ad};return W}function i(T){var W=[],S=[];if(T.tripleQuotedStrings){W.push([C,/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,null,"'\""])}else{if(T.multiLineStrings){W.push([C,/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,"'\"`"])}else{W.push([C,/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,"\"'"])}}if(T.verbatimStrings){S.push([C,/^@\"(?:[^\"]|\"\")*(?:\"|$)/,null])}var Y=T.hashComments;if(Y){if(T.cStyleComments){if(Y>1){W.push([j,/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,null,"#"])}else{W.push([j,/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\r\n]*)/,null,"#"])}S.push([C,/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,null])}else{W.push([j,/^#[^\r\n]*/,null,"#"])}}if(T.cStyleComments){S.push([j,/^\/\/[^\r\n]*/,null]);S.push([j,/^\/\*[\s\S]*?(?:\*\/|$)/,null])}if(T.regexLiterals){var X=("/(?=[^/*])(?:[^/\\x5B\\x5C]|\\x5C[\\s\\S]|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+/");S.push(["lang-regex",new RegExp("^"+M+"("+X+")")])}var V=T.types;if(V){S.push([O,V])}var U=(""+T.keywords).replace(/^ | $/g,"");if(U.length){S.push([z,new RegExp("^(?:"+U.replace(/[\s,]+/g,"|")+")\\b"),null])}W.push([F,/^\s+/,null," \r\n\t\xA0"]);S.push([G,/^@[a-z_$][a-z_$@0-9]*/i,null],[O,/^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/,null],[F,/^[a-z_$][a-z_$@0-9]*/i,null],[G,new RegExp("^(?:0x[a-f0-9]+|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)(?:e[+\\-]?\\d+)?)[a-z]*","i"),null,"0123456789"],[F,/^\\[\s\S]?/,null],[L,/^.[^\s\w\.$@\'\"\`\/\#\\]*/,null]);return g(W,S)}var K=i({keywords:A,hashComments:true,cStyleComments:true,multiLineStrings:true,regexLiterals:true});function Q(V,ag){var U=/(?:^|\s)nocode(?:\s|$)/;var ab=/\r\n?|\n/;var ac=V.ownerDocument;var S;if(V.currentStyle){S=V.currentStyle.whiteSpace}else{if(window.getComputedStyle){S=ac.defaultView.getComputedStyle(V,null).getPropertyValue("white-space")}}var Z=S&&"pre"===S.substring(0,3);var af=ac.createElement("LI");while(V.firstChild){af.appendChild(V.firstChild)}var W=[af];function ae(al){switch(al.nodeType){case 1:if(U.test(al.className)){break}if("BR"===al.nodeName){ad(al);if(al.parentNode){al.parentNode.removeChild(al)}}else{for(var an=al.firstChild;an;an=an.nextSibling){ae(an)}}break;case 3:case 4:if(Z){var am=al.nodeValue;var aj=am.match(ab);if(aj){var ai=am.substring(0,aj.index);al.nodeValue=ai;var ah=am.substring(aj.index+aj[0].length);if(ah){var ak=al.parentNode;ak.insertBefore(ac.createTextNode(ah),al.nextSibling)}ad(al);if(!ai){al.parentNode.removeChild(al)}}}break}}function ad(ak){while(!ak.nextSibling){ak=ak.parentNode;if(!ak){return}}function ai(al,ar){var aq=ar?al.cloneNode(false):al;var ao=al.parentNode;if(ao){var ap=ai(ao,1);var an=al.nextSibling;ap.appendChild(aq);for(var am=an;am;am=an){an=am.nextSibling;ap.appendChild(am)}}return aq}var ah=ai(ak.nextSibling,0);for(var aj;(aj=ah.parentNode)&&aj.nodeType===1;){ah=aj}W.push(ah)}for(var Y=0;Y=S){ah+=2}if(V>=ap){Z+=2}}}var t={};function c(U,V){for(var S=V.length;--S>=0;){var T=V[S];if(!t.hasOwnProperty(T)){t[T]=U}else{if(window.console){console.warn("cannot override language handler %s",T)}}}}function q(T,S){if(!(T&&t.hasOwnProperty(T))){T=/^\s*]*(?:>|$)/],[j,/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],[L,/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);c(g([[F,/^[\s]+/,null," \t\r\n"],[n,/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,null,"\"'"]],[[m,/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],[P,/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],[L,/^[=<>\/]+/],["lang-js",/^on\w+\s*=\s*\"([^\"]+)\"/i],["lang-js",/^on\w+\s*=\s*\'([^\']+)\'/i],["lang-js",/^on\w+\s*=\s*([^\"\'>\s]+)/i],["lang-css",/^style\s*=\s*\"([^\"]+)\"/i],["lang-css",/^style\s*=\s*\'([^\']+)\'/i],["lang-css",/^style\s*=\s*([^\"\'>\s]+)/i]]),["in.tag"]);c(g([],[[n,/^[\s\S]+/]]),["uq.val"]);c(i({keywords:l,hashComments:true,cStyleComments:true,types:e}),["c","cc","cpp","cxx","cyc","m"]);c(i({keywords:"null,true,false"}),["json"]);c(i({keywords:R,hashComments:true,cStyleComments:true,verbatimStrings:true,types:e}),["cs"]);c(i({keywords:x,cStyleComments:true}),["java"]);c(i({keywords:H,hashComments:true,multiLineStrings:true}),["bsh","csh","sh"]);c(i({keywords:I,hashComments:true,multiLineStrings:true,tripleQuotedStrings:true}),["cv","py"]);c(i({keywords:s,hashComments:true,multiLineStrings:true,regexLiterals:true}),["perl","pl","pm"]);c(i({keywords:f,hashComments:true,multiLineStrings:true,regexLiterals:true}),["rb"]);c(i({keywords:w,cStyleComments:true,regexLiterals:true}),["js"]);c(i({keywords:r,hashComments:3,cStyleComments:true,multilineStrings:true,tripleQuotedStrings:true,regexLiterals:true}),["coffee"]);c(g([],[[C,/^[\s\S]+/]]),["regex"]);function d(V){var U=V.langExtension;try{var S=a(V.sourceNode);var T=S.sourceCode;V.sourceCode=T;V.spans=S.spans;V.basePos=0;q(U,T)(V);D(V)}catch(W){if("console" in window){console.log(W&&W.stack?W.stack:W)}}}function y(W,V,U){var S=document.createElement("PRE");S.innerHTML=W;if(U){Q(S,U)}var T={langExtension:V,numberLines:U,sourceNode:S};d(T);return S.innerHTML}function b(ad){function Y(af){return document.getElementsByTagName(af)}var ac=[Y("pre"),Y("code"),Y("xmp")];var T=[];for(var aa=0;aa=0){var ah=ai.match(ab);var am;if(!ah&&(am=o(aj))&&"CODE"===am.tagName){ah=am.className.match(ab)}if(ah){ah=ah[1]}var al=false;for(var ak=aj.parentNode;ak;ak=ak.parentNode){if((ak.tagName==="pre"||ak.tagName==="code"||ak.tagName==="xmp")&&ak.className&&ak.className.indexOf("prettyprint")>=0){al=true;break}}if(!al){var af=aj.className.match(/\blinenums\b(?::(\d+))?/);af=af?af[1]&&af[1].length?+af[1]:true:false;if(af){Q(aj,af)}S={langExtension:ah,sourceNode:aj,numberLines:af};d(S)}}}if(X]*(?:>|$)/],[PR.PR_COMMENT,/^<\!--[\s\S]*?(?:-\->|$)/],[PR.PR_PUNCTUATION,/^(?:<[%?]|[%?]>)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-handlebars",/^]*type\s*=\s*['"]?text\/x-handlebars-template['"]?\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i],[PR.PR_DECLARATION,/^{{[#^>/]?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{&?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{{>?\s*[\w.][^}]*}}}/],[PR.PR_COMMENT,/^{{![^}]*}}/]]),["handlebars","hbs"]);PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[ \t\r\n\f]+/,null," \t\r\n\f"]],[[PR.PR_STRING,/^\"(?:[^\n\r\f\\\"]|\\(?:\r\n?|\n|\f)|\\[\s\S])*\"/,null],[PR.PR_STRING,/^\'(?:[^\n\r\f\\\']|\\(?:\r\n?|\n|\f)|\\[\s\S])*\'/,null],["lang-css-str",/^url\(([^\)\"\']*)\)/i],[PR.PR_KEYWORD,/^(?:url|rgb|\!important|@import|@page|@media|@charset|inherit)(?=[^\-\w]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|(?:\\[0-9a-f]+ ?))(?:[_a-z0-9\-]|\\(?:\\[0-9a-f]+ ?))*)\s*:/i],[PR.PR_COMMENT,/^\/\*[^*]*\*+(?:[^\/*][^*]*\*+)*\//],[PR.PR_COMMENT,/^(?:)/],[PR.PR_LITERAL,/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],[PR.PR_LITERAL,/^#(?:[0-9a-f]{3}){1,2}/i],[PR.PR_PLAIN,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i],[PR.PR_PUNCTUATION,/^[^\s\w\'\"]+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_KEYWORD,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_STRING,/^[^\)\"\']+/]]),["css-str"]); 3 | -------------------------------------------------------------------------------- /coverage/lcov-report/sort-arrow-sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snotra-org/hasura-parser/a17e821f278691bd69d3465c866888af05a361d2/coverage/lcov-report/sort-arrow-sprite.png -------------------------------------------------------------------------------- /coverage/lcov-report/sorter.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | var addSorting = (function() { 3 | 'use strict'; 4 | var cols, 5 | currentSort = { 6 | index: 0, 7 | desc: false 8 | }; 9 | 10 | // returns the summary table element 11 | function getTable() { 12 | return document.querySelector('.coverage-summary'); 13 | } 14 | // returns the thead element of the summary table 15 | function getTableHeader() { 16 | return getTable().querySelector('thead tr'); 17 | } 18 | // returns the tbody element of the summary table 19 | function getTableBody() { 20 | return getTable().querySelector('tbody'); 21 | } 22 | // returns the th element for nth column 23 | function getNthColumn(n) { 24 | return getTableHeader().querySelectorAll('th')[n]; 25 | } 26 | 27 | // loads all columns 28 | function loadColumns() { 29 | var colNodes = getTableHeader().querySelectorAll('th'), 30 | colNode, 31 | cols = [], 32 | col, 33 | i; 34 | 35 | for (i = 0; i < colNodes.length; i += 1) { 36 | colNode = colNodes[i]; 37 | col = { 38 | key: colNode.getAttribute('data-col'), 39 | sortable: !colNode.getAttribute('data-nosort'), 40 | type: colNode.getAttribute('data-type') || 'string' 41 | }; 42 | cols.push(col); 43 | if (col.sortable) { 44 | col.defaultDescSort = col.type === 'number'; 45 | colNode.innerHTML = 46 | colNode.innerHTML + ''; 47 | } 48 | } 49 | return cols; 50 | } 51 | // attaches a data attribute to every tr element with an object 52 | // of data values keyed by column name 53 | function loadRowData(tableRow) { 54 | var tableCols = tableRow.querySelectorAll('td'), 55 | colNode, 56 | col, 57 | data = {}, 58 | i, 59 | val; 60 | for (i = 0; i < tableCols.length; i += 1) { 61 | colNode = tableCols[i]; 62 | col = cols[i]; 63 | val = colNode.getAttribute('data-value'); 64 | if (col.type === 'number') { 65 | val = Number(val); 66 | } 67 | data[col.key] = val; 68 | } 69 | return data; 70 | } 71 | // loads all row data 72 | function loadData() { 73 | var rows = getTableBody().querySelectorAll('tr'), 74 | i; 75 | 76 | for (i = 0; i < rows.length; i += 1) { 77 | rows[i].data = loadRowData(rows[i]); 78 | } 79 | } 80 | // sorts the table using the data for the ith column 81 | function sortByIndex(index, desc) { 82 | var key = cols[index].key, 83 | sorter = function(a, b) { 84 | a = a.data[key]; 85 | b = b.data[key]; 86 | return a < b ? -1 : a > b ? 1 : 0; 87 | }, 88 | finalSorter = sorter, 89 | tableBody = document.querySelector('.coverage-summary tbody'), 90 | rowNodes = tableBody.querySelectorAll('tr'), 91 | rows = [], 92 | i; 93 | 94 | if (desc) { 95 | finalSorter = function(a, b) { 96 | return -1 * sorter(a, b); 97 | }; 98 | } 99 | 100 | for (i = 0; i < rowNodes.length; i += 1) { 101 | rows.push(rowNodes[i]); 102 | tableBody.removeChild(rowNodes[i]); 103 | } 104 | 105 | rows.sort(finalSorter); 106 | 107 | for (i = 0; i < rows.length; i += 1) { 108 | tableBody.appendChild(rows[i]); 109 | } 110 | } 111 | // removes sort indicators for current column being sorted 112 | function removeSortIndicators() { 113 | var col = getNthColumn(currentSort.index), 114 | cls = col.className; 115 | 116 | cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, ''); 117 | col.className = cls; 118 | } 119 | // adds sort indicators for current column being sorted 120 | function addSortIndicators() { 121 | getNthColumn(currentSort.index).className += currentSort.desc 122 | ? ' sorted-desc' 123 | : ' sorted'; 124 | } 125 | // adds event listeners for all sorter widgets 126 | function enableUI() { 127 | var i, 128 | el, 129 | ithSorter = function ithSorter(i) { 130 | var col = cols[i]; 131 | 132 | return function() { 133 | var desc = col.defaultDescSort; 134 | 135 | if (currentSort.index === i) { 136 | desc = !currentSort.desc; 137 | } 138 | sortByIndex(i, desc); 139 | removeSortIndicators(); 140 | currentSort.index = i; 141 | currentSort.desc = desc; 142 | addSortIndicators(); 143 | }; 144 | }; 145 | for (i = 0; i < cols.length; i += 1) { 146 | if (cols[i].sortable) { 147 | // add the click event handler on the th so users 148 | // dont have to click on those tiny arrows 149 | el = getNthColumn(i).querySelector('.sorter').parentElement; 150 | if (el.addEventListener) { 151 | el.addEventListener('click', ithSorter(i)); 152 | } else { 153 | el.attachEvent('onclick', ithSorter(i)); 154 | } 155 | } 156 | } 157 | } 158 | // adds sorting functionality to the UI 159 | return function() { 160 | if (!getTable()) { 161 | return; 162 | } 163 | cols = loadColumns(); 164 | loadData(); 165 | addSortIndicators(); 166 | enableUI(); 167 | }; 168 | })(); 169 | 170 | window.addEventListener('load', addSorting); 171 | -------------------------------------------------------------------------------- /coverage/lcov-report/types.ts.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Code coverage report for types.ts 7 | 8 | 9 | 10 | 11 | 12 | 17 | 18 | 19 | 20 |
21 |
22 |

All files types.ts

23 |
24 | 25 |
26 | 100% 27 | Statements 28 | 14/14 29 |
30 | 31 | 32 |
33 | 100% 34 | Branches 35 | 6/6 36 |
37 | 38 | 39 |
40 | 100% 41 | Functions 42 | 3/3 43 |
44 | 45 | 46 |
47 | 100% 48 | Lines 49 | 14/14 50 |
51 | 52 | 53 |
54 |

55 | Press n or j to go to the next uncovered block, b, p or k for the previous block. 56 |

57 |
58 |
59 |

 60 | 
1 61 | 2 62 | 3 63 | 4 64 | 5 65 | 6 66 | 7 67 | 8 68 | 9 69 | 10 70 | 11 71 | 12 72 | 13 73 | 14 74 | 15 75 | 16 76 | 17 77 | 18 78 | 19 79 | 20 80 | 21 81 | 22 82 | 23 83 | 24 84 | 25 85 | 26 86 | 27 87 | 28 88 | 29 89 | 30 90 | 31 91 | 32 92 | 33 93 | 34 94 | 35 95 | 36 96 | 37 97 | 38 98 | 39 99 | 40 100 | 41 101 | 42 102 | 43 103 | 44 104 | 45 105 | 46 106 | 47 107 | 48 108 | 49 109 | 50 110 | 51 111 | 52 112 | 53 113 | 54 114 | 55 115 | 56 116 | 57 117 | 58 118 | 59 119 | 60 120 | 61 121 | 62 122 | 63 123 | 64 124 | 65 125 | 66 126 | 67 127 | 68 128 | 69 129 | 70 130 | 71 131 | 72 132 | 73 133 | 74 134 | 75 135 | 76 136 | 77 137 | 78 138 | 79 139 | 80 140 | 81 141 | 82 142 | 83 143 | 84 144 | 85  145 |   146 |   147 |   148 |   149 |   150 |   151 |   152 |   153 |   154 |   155 |   156 |   157 |   158 |   159 |   160 |   161 |   162 |   163 |   164 |   165 |   166 |   167 |   168 |   169 |   170 |   171 |   172 |   173 |   174 |   175 |   176 |   177 |   178 |   179 |   180 |   181 |   182 |   183 |   184 |   185 |   186 |   187 |   188 |   189 |   190 |   191 |   192 |   193 |   194 |   195 |   196 |   197 |   198 |   199 |   200 |   201 | 1x 202 | 1x 203 | 1x 204 | 1x 205 | 1x 206 |   207 |   208 | 1x 209 | 1x 210 | 1x 211 |   212 |   213 | 1x 214 | 1x 215 | 1x 216 |   217 |   218 |   219 | 1x 220 |   221 | 1x 222 |   223 |   224 |   225 |   226 |   227 | 1x 228 |  
/**
229 |  * Hasura Action Event types
230 |  */
231 | type HasuraAction = {
232 | 	session_variables: any,
233 | 	input: any,
234 | 	action: HasuraActionData
235 | }
236 |  
237 | type HasuraActionData = {
238 | 	name: string
239 | }
240 |  
241 | /**
242 |  * Hasura Event Trigger types
243 |  */
244 |  
245 | type HasuraEvent = {
246 | 	event: HasuraEventData,
247 | 	created_at: string,
248 | 	id: string,
249 | 	trigger: HasuraEventTrigger,
250 | 	table: HasuraEventTable,
251 | 	trace_context: HasuraEventTraceContext
252 | 	delivery_info?: HasuraEventDeliveryInfo
253 | }
254 |  
255 | type HasuraEventTraceContext = {
256 | 	trace_id: number,
257 | 	span_id: number
258 | }
259 |  
260 | type HasuraEventDeliveryInfo = {
261 | 	max_retries: number,
262 | 	current_retry: number
263 | }
264 |  
265 | type HasuraEventTrigger = {
266 | 	name: string
267 | }
268 |  
269 | type HasuraEventTable = {
270 | 	schema: string,
271 | 	name: string
272 | }
273 |  
274 | type HasuraEventData = {
275 | 	session_variables: any,
276 | 	op: HasuraEventOperationType,
277 | 	data: HasuraEventPayload
278 | }
279 |  
280 | type HasuraEventPayload = {
281 | 	old: any,
282 | 	new: any
283 | }
284 |  
285 | enum HasuraEventOperationType {
286 | 	UPDATE = "UPDATE",
287 | 	INSERT = "INSERT",
288 | 	DELETE = "DELETE",
289 | 	MANUAL = "MANUAL"
290 | }
291 |  
292 | enum HasuraSessionTypes {
293 | 	ROLE = "x-hasura-role",
294 | 	USERID = "x-hasura-user-id"
295 | }
296 |  
297 | enum HasuraDataType {
298 | 	NEW = "new",
299 | 	OLD = "old"
300 | }
301 |  
302 | export {
303 | 	HasuraDataType,
304 | 	HasuraAction,
305 | 	HasuraSessionTypes,
306 | 	HasuraEvent,
307 | 	HasuraEventTrigger,
308 | 	HasuraEventTable,
309 | 	HasuraEventData,
310 | 	HasuraEventPayload,
311 | 	HasuraEventOperationType
312 | }
313 | 314 |
315 |
316 | 321 | 322 | 323 | 328 | 329 | 330 | 331 | 332 | -------------------------------------------------------------------------------- /coverage/lcov.info: -------------------------------------------------------------------------------- 1 | TN: 2 | SF:src/action.ts 3 | FN:5,(anonymous_0) 4 | FN:8,ActionParser 5 | FN:16,(anonymous_2) 6 | FN:23,(anonymous_3) 7 | FN:30,(anonymous_4) 8 | FN:39,(anonymous_5) 9 | FN:66,(anonymous_6) 10 | FNF:7 11 | FNH:7 12 | FNDA:1,(anonymous_0) 13 | FNDA:7,ActionParser 14 | FNDA:2,(anonymous_2) 15 | FNDA:1,(anonymous_3) 16 | FNDA:1,(anonymous_4) 17 | FNDA:2,(anonymous_5) 18 | FNDA:2,(anonymous_6) 19 | DA:5,1 20 | DA:9,7 21 | DA:16,1 22 | DA:17,2 23 | DA:23,1 24 | DA:24,1 25 | DA:30,1 26 | DA:31,1 27 | DA:39,10 28 | DA:42,2 29 | DA:45,2 30 | DA:46,1 31 | DA:48,1 32 | DA:51,2 33 | DA:52,6 34 | DA:53,6 35 | DA:54,4 36 | DA:56,2 37 | DA:60,2 38 | DA:66,1 39 | DA:67,2 40 | DA:68,1 41 | DA:70,1 42 | DA:73,1 43 | DA:75,1 44 | LF:25 45 | LH:25 46 | BRDA:45,0,0,1 47 | BRDA:45,0,1,1 48 | BRDA:53,1,0,4 49 | BRDA:53,1,1,2 50 | BRDA:67,2,0,1 51 | BRDA:67,2,1,1 52 | BRF:6 53 | BRH:6 54 | end_of_record 55 | TN: 56 | SF:src/event.ts 57 | FN:7,(anonymous_0) 58 | FN:10,EventParser 59 | FN:17,(anonymous_2) 60 | FN:24,(anonymous_3) 61 | FN:31,(anonymous_4) 62 | FN:38,(anonymous_5) 63 | FN:45,(anonymous_6) 64 | FN:53,(anonymous_7) 65 | FN:60,(anonymous_8) 66 | FN:67,(anonymous_9) 67 | FN:74,(anonymous_10) 68 | FN:81,(anonymous_11) 69 | FN:88,(anonymous_12) 70 | FN:95,(anonymous_13) 71 | FN:102,(anonymous_14) 72 | FN:109,(anonymous_15) 73 | FN:116,(anonymous_16) 74 | FN:123,(anonymous_17) 75 | FN:130,(anonymous_18) 76 | FN:137,(anonymous_19) 77 | FN:141,(anonymous_20) 78 | FN:153,(anonymous_21) 79 | FN:168,(anonymous_22) 80 | FN:193,(anonymous_23) 81 | FNF:24 82 | FNH:24 83 | FNDA:1,(anonymous_0) 84 | FNDA:22,EventParser 85 | FNDA:4,(anonymous_2) 86 | FNDA:5,(anonymous_3) 87 | FNDA:1,(anonymous_4) 88 | FNDA:3,(anonymous_5) 89 | FNDA:14,(anonymous_6) 90 | FNDA:3,(anonymous_7) 91 | FNDA:1,(anonymous_8) 92 | FNDA:1,(anonymous_9) 93 | FNDA:1,(anonymous_10) 94 | FNDA:1,(anonymous_11) 95 | FNDA:1,(anonymous_12) 96 | FNDA:2,(anonymous_13) 97 | FNDA:2,(anonymous_14) 98 | FNDA:1,(anonymous_15) 99 | FNDA:1,(anonymous_16) 100 | FNDA:1,(anonymous_17) 101 | FNDA:1,(anonymous_18) 102 | FNDA:1,(anonymous_19) 103 | FNDA:4,(anonymous_20) 104 | FNDA:5,(anonymous_21) 105 | FNDA:1,(anonymous_22) 106 | FNDA:4,(anonymous_23) 107 | DA:1,1 108 | DA:7,1 109 | DA:11,22 110 | DA:17,1 111 | DA:18,4 112 | DA:24,1 113 | DA:25,5 114 | DA:31,1 115 | DA:32,1 116 | DA:38,1 117 | DA:39,3 118 | DA:45,1 119 | DA:46,14 120 | DA:53,1 121 | DA:54,3 122 | DA:60,1 123 | DA:61,1 124 | DA:67,1 125 | DA:68,1 126 | DA:74,1 127 | DA:75,1 128 | DA:81,1 129 | DA:82,1 130 | DA:88,1 131 | DA:89,1 132 | DA:95,1 133 | DA:96,2 134 | DA:102,1 135 | DA:103,2 136 | DA:109,1 137 | DA:110,1 138 | DA:116,1 139 | DA:117,1 140 | DA:123,1 141 | DA:124,1 142 | DA:130,1 143 | DA:131,1 144 | DA:137,1 145 | DA:138,1 146 | DA:141,1 147 | DA:142,4 148 | DA:143,3 149 | DA:145,1 150 | DA:153,22 151 | DA:154,5 152 | DA:155,1 153 | DA:157,4 154 | DA:158,4 155 | DA:168,1 156 | DA:169,1 157 | DA:174,1 158 | DA:175,2 159 | DA:176,2 160 | DA:177,1 161 | DA:178,1 162 | DA:180,1 163 | DA:181,1 164 | DA:184,1 165 | DA:193,1 166 | DA:194,4 167 | DA:196,4 168 | DA:197,10 169 | DA:198,10 170 | DA:199,6 171 | DA:201,4 172 | DA:205,4 173 | DA:209,1 174 | DA:211,1 175 | LF:68 176 | LH:68 177 | BRDA:96,0,0,1 178 | BRDA:96,0,1,1 179 | BRDA:96,1,0,2 180 | BRDA:96,1,1,2 181 | BRDA:103,2,0,1 182 | BRDA:103,2,1,1 183 | BRDA:103,3,0,2 184 | BRDA:103,3,1,2 185 | BRDA:142,4,0,3 186 | BRDA:142,4,1,1 187 | BRDA:142,5,0,4 188 | BRDA:142,5,1,2 189 | BRDA:154,6,0,1 190 | BRDA:154,6,1,4 191 | BRDA:176,7,0,1 192 | BRDA:176,7,1,1 193 | BRDA:176,8,0,2 194 | BRDA:176,8,1,1 195 | BRDA:198,9,0,6 196 | BRDA:198,9,1,4 197 | BRF:20 198 | BRH:20 199 | end_of_record 200 | TN: 201 | SF:src/types.ts 202 | FN:58,(anonymous_0) 203 | FN:65,(anonymous_1) 204 | FN:70,(anonymous_2) 205 | FNF:3 206 | FNH:3 207 | FNDA:1,(anonymous_0) 208 | FNDA:1,(anonymous_1) 209 | FNDA:1,(anonymous_2) 210 | DA:58,1 211 | DA:59,1 212 | DA:60,1 213 | DA:61,1 214 | DA:62,1 215 | DA:65,1 216 | DA:66,1 217 | DA:67,1 218 | DA:70,1 219 | DA:71,1 220 | DA:72,1 221 | DA:76,1 222 | DA:78,1 223 | DA:84,1 224 | LF:14 225 | LH:14 226 | BRDA:58,0,0,1 227 | BRDA:58,0,1,1 228 | BRDA:65,1,0,1 229 | BRDA:65,1,1,1 230 | BRDA:70,2,0,1 231 | BRDA:70,2,1,1 232 | BRF:6 233 | BRH:6 234 | end_of_record 235 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | transform: {'^.+\\.ts?$': 'ts-jest'}, 3 | testEnvironment: 'node', 4 | testRegex: '/tests/.*\\.(test|spec)?\\.(ts|tsx)$', 5 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'] 6 | }; -------------------------------------------------------------------------------- /lib/action.d.ts: -------------------------------------------------------------------------------- 1 | import { HasuraAction } from './types'; 2 | declare class ActionParser { 3 | private payload; 4 | constructor(payload: HasuraAction); 5 | /** 6 | * Returns session variable by ID. 7 | * @param id ID of session variable (e.g. x-hasura-user-role). 8 | */ 9 | getSessionVariable(id: string): string; 10 | /** 11 | * Returns all session variables. 12 | */ 13 | getSessionVariables(): any; 14 | /** 15 | * Returns action name. 16 | */ 17 | getActionName(): string; 18 | /** 19 | * Gets data from action for provided keys. 20 | * 21 | * @param keys Keys to fetch. 22 | */ 23 | getData(...keys: Array): any; 24 | /** 25 | * Returns raw data from payload (not fetching by keys we need.) 26 | */ 27 | getRawData(): any; 28 | } 29 | export default ActionParser; 30 | -------------------------------------------------------------------------------- /lib/action.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | var ActionParser = /** @class */ (function () { 4 | function ActionParser(payload) { 5 | this.payload = payload; 6 | } 7 | /** 8 | * Returns session variable by ID. 9 | * @param id ID of session variable (e.g. x-hasura-user-role). 10 | */ 11 | ActionParser.prototype.getSessionVariable = function (id) { 12 | return this.payload.session_variables[id]; 13 | }; 14 | /** 15 | * Returns all session variables. 16 | */ 17 | ActionParser.prototype.getSessionVariables = function () { 18 | return this.payload.session_variables; 19 | }; 20 | /** 21 | * Returns action name. 22 | */ 23 | ActionParser.prototype.getActionName = function () { 24 | return this.payload.action.name; 25 | }; 26 | /** 27 | * Gets data from action for provided keys. 28 | * 29 | * @param keys Keys to fetch. 30 | */ 31 | ActionParser.prototype.getData = function () { 32 | var keys = []; 33 | for (var _i = 0; _i < arguments.length; _i++) { 34 | keys[_i] = arguments[_i]; 35 | } 36 | var payload; 37 | var data = {}; 38 | // Some people prefer to do input on mutations and other operations 39 | if (this.payload.input.input) { 40 | payload = this.payload.input.input; 41 | } 42 | else { 43 | payload = this.payload.input; 44 | } 45 | for (var i = 0; i < keys.length; i++) { 46 | var key = keys[i]; 47 | if (payload[key]) { 48 | data[key] = payload[key]; 49 | } 50 | else { 51 | data[key] = null; 52 | } 53 | } 54 | return data; 55 | }; 56 | /** 57 | * Returns raw data from payload (not fetching by keys we need.) 58 | */ 59 | ActionParser.prototype.getRawData = function () { 60 | if (this.payload.input.input) { 61 | return this.payload.input.input; 62 | } 63 | return this.payload.input; 64 | }; 65 | return ActionParser; 66 | }()); 67 | exports.default = ActionParser; 68 | -------------------------------------------------------------------------------- /lib/event.d.ts: -------------------------------------------------------------------------------- 1 | import { HasuraEvent } from './types'; 2 | declare class EventParser { 3 | private payload; 4 | constructor(payload: HasuraEvent); 5 | /** 6 | * Returns if operation is an INSERT. 7 | */ 8 | isInsertOperation(): boolean; 9 | /** 10 | * Checks if operation is an UPDATE. 11 | */ 12 | isUpdateOperation(): boolean; 13 | /** 14 | * Checks if operation is a DELETE. 15 | */ 16 | isDeleteOperation(): boolean; 17 | /** 18 | * Checks if operation is MANUAL. 19 | */ 20 | isManualOperation(): boolean; 21 | /** 22 | * Returns operation type. 23 | */ 24 | getOperationType(): string; 25 | /** 26 | * Returns session variable by provided ID (e.g. x-hasura-user-role). 27 | * @param id ID of session variable. 28 | */ 29 | getSessionVariable(id: string): string; 30 | /** 31 | * Returns all session variables. 32 | */ 33 | getSessionVariables(): any; 34 | /** 35 | * Returns ID of payload. 36 | */ 37 | getID(): string; 38 | /** 39 | * Returns trigger name (set in Hasura Console). 40 | */ 41 | getTriggerName(): string; 42 | /** 43 | * Gets schema name that the event affected. 44 | */ 45 | getSchemaName(): string; 46 | /** 47 | * Gets table name that the event affected. 48 | */ 49 | getTableName(): string; 50 | /** 51 | * Returns current retry of the event (if it is set in Hasura Console). 52 | */ 53 | getCurrentRetry(): number | undefined; 54 | /** 55 | * Returns max retries for current event. 56 | */ 57 | getMaxRetries(): number | undefined; 58 | /** 59 | * Returns raw data (old - in UPDATE, DELETE and MANUAL events). 60 | */ 61 | getOldData(): any; 62 | /** 63 | * Returns raw data (new - in INSERT, UPDATE events). 64 | */ 65 | getNewData(): any; 66 | /** 67 | * Returns timestamp of event. 68 | */ 69 | getTimestamp(): string; 70 | /** 71 | * Returns trace data - context ID. 72 | */ 73 | getTraceContextID(): number; 74 | /** 75 | * Returns trace data - span context ID. 76 | */ 77 | getTraceContextSpanID(): number; 78 | private getDataFetchType; 79 | /** 80 | * Fetches data that was sent by Hasura event by the keys provided. 81 | * 82 | * @param keys Data to fetch. 83 | */ 84 | getData(...keys: Array): any; 85 | /** 86 | * Fetches update data by keys. If a key does not exist in both new 87 | * and old the value is set to null and an info message is triggered. 88 | * 89 | * @param keys Keys to fetch. 90 | */ 91 | private getUData; 92 | /** 93 | * Fetches data for an INSERT, DELETE or MANUAL operation. 94 | * 95 | * @param keys Keys to fetch. 96 | * @param type Type of operation. 97 | */ 98 | private getIDMData; 99 | } 100 | export default EventParser; 101 | -------------------------------------------------------------------------------- /lib/event.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | var types_1 = require("./types"); 4 | var EventParser = /** @class */ (function () { 5 | function EventParser(payload) { 6 | this.payload = payload; 7 | } 8 | /** 9 | * Returns if operation is an INSERT. 10 | */ 11 | EventParser.prototype.isInsertOperation = function () { 12 | return this.getOperationType() === types_1.HasuraEventOperationType.INSERT; 13 | }; 14 | /** 15 | * Checks if operation is an UPDATE. 16 | */ 17 | EventParser.prototype.isUpdateOperation = function () { 18 | return this.getOperationType() === types_1.HasuraEventOperationType.UPDATE; 19 | }; 20 | /** 21 | * Checks if operation is a DELETE. 22 | */ 23 | EventParser.prototype.isDeleteOperation = function () { 24 | return this.getOperationType() === types_1.HasuraEventOperationType.DELETE; 25 | }; 26 | /** 27 | * Checks if operation is MANUAL. 28 | */ 29 | EventParser.prototype.isManualOperation = function () { 30 | return this.getOperationType() === types_1.HasuraEventOperationType.MANUAL; 31 | }; 32 | /** 33 | * Returns operation type. 34 | */ 35 | EventParser.prototype.getOperationType = function () { 36 | return this.payload.event.op; 37 | }; 38 | /** 39 | * Returns session variable by provided ID (e.g. x-hasura-user-role). 40 | * @param id ID of session variable. 41 | */ 42 | EventParser.prototype.getSessionVariable = function (id) { 43 | return this.payload.event.session_variables[id]; 44 | }; 45 | /** 46 | * Returns all session variables. 47 | */ 48 | EventParser.prototype.getSessionVariables = function () { 49 | return this.payload.event.session_variables; 50 | }; 51 | /** 52 | * Returns ID of payload. 53 | */ 54 | EventParser.prototype.getID = function () { 55 | return this.payload.id; 56 | }; 57 | /** 58 | * Returns trigger name (set in Hasura Console). 59 | */ 60 | EventParser.prototype.getTriggerName = function () { 61 | return this.payload.trigger.name; 62 | }; 63 | /** 64 | * Gets schema name that the event affected. 65 | */ 66 | EventParser.prototype.getSchemaName = function () { 67 | return this.payload.table.schema; 68 | }; 69 | /** 70 | * Gets table name that the event affected. 71 | */ 72 | EventParser.prototype.getTableName = function () { 73 | return this.payload.table.name; 74 | }; 75 | /** 76 | * Returns current retry of the event (if it is set in Hasura Console). 77 | */ 78 | EventParser.prototype.getCurrentRetry = function () { 79 | var _a; 80 | return (_a = this.payload.delivery_info) === null || _a === void 0 ? void 0 : _a.current_retry; 81 | }; 82 | /** 83 | * Returns max retries for current event. 84 | */ 85 | EventParser.prototype.getMaxRetries = function () { 86 | var _a; 87 | return (_a = this.payload.delivery_info) === null || _a === void 0 ? void 0 : _a.max_retries; 88 | }; 89 | /** 90 | * Returns raw data (old - in UPDATE, DELETE and MANUAL events). 91 | */ 92 | EventParser.prototype.getOldData = function () { 93 | return this.payload.event.data.old; 94 | }; 95 | /** 96 | * Returns raw data (new - in INSERT, UPDATE events). 97 | */ 98 | EventParser.prototype.getNewData = function () { 99 | return this.payload.event.data.new; 100 | }; 101 | /** 102 | * Returns timestamp of event. 103 | */ 104 | EventParser.prototype.getTimestamp = function () { 105 | return this.payload.created_at; 106 | }; 107 | /** 108 | * Returns trace data - context ID. 109 | */ 110 | EventParser.prototype.getTraceContextID = function () { 111 | return this.payload.trace_context.trace_id; 112 | }; 113 | /** 114 | * Returns trace data - span context ID. 115 | */ 116 | EventParser.prototype.getTraceContextSpanID = function () { 117 | return this.payload.trace_context.span_id; 118 | }; 119 | EventParser.prototype.getDataFetchType = function () { 120 | if (this.isInsertOperation() || this.isManualOperation()) { 121 | return types_1.HasuraDataType.NEW; 122 | } 123 | return types_1.HasuraDataType.OLD; 124 | }; 125 | /** 126 | * Fetches data that was sent by Hasura event by the keys provided. 127 | * 128 | * @param keys Data to fetch. 129 | */ 130 | EventParser.prototype.getData = function () { 131 | var keys = []; 132 | for (var _i = 0; _i < arguments.length; _i++) { 133 | keys[_i] = arguments[_i]; 134 | } 135 | if (this.isUpdateOperation()) { 136 | return this.getUData(keys); 137 | } 138 | else { 139 | var type = this.getDataFetchType(); 140 | return this.getIDMData(keys, type); 141 | } 142 | }; 143 | /** 144 | * Fetches update data by keys. If a key does not exist in both new 145 | * and old the value is set to null and an info message is triggered. 146 | * 147 | * @param keys Keys to fetch. 148 | */ 149 | EventParser.prototype.getUData = function (keys) { 150 | var data = { 151 | old: {}, 152 | new: {} 153 | }; 154 | for (var i = 0; i < keys.length; i++) { 155 | var key = keys[i]; 156 | if (this.payload.event.data.old[key] && this.payload.event.data.new[key]) { 157 | data.old[key] = this.payload.event.data.old[key]; 158 | data.new[key] = this.payload.event.data.new[key]; 159 | } 160 | else { 161 | data.old[key] = null; 162 | data.new[key] = null; 163 | } 164 | } 165 | return data; 166 | }; 167 | /** 168 | * Fetches data for an INSERT, DELETE or MANUAL operation. 169 | * 170 | * @param keys Keys to fetch. 171 | * @param type Type of operation. 172 | */ 173 | EventParser.prototype.getIDMData = function (keys, type) { 174 | var data = {}; 175 | for (var i = 0; i < keys.length; i++) { 176 | var key = keys[i]; 177 | if (this.payload.event.data[type][key]) { 178 | data[key] = this.payload.event.data[type][key]; 179 | } 180 | else { 181 | data[key] = null; 182 | } 183 | } 184 | return data; 185 | }; 186 | return EventParser; 187 | }()); 188 | exports.default = EventParser; 189 | -------------------------------------------------------------------------------- /lib/index.d.ts: -------------------------------------------------------------------------------- 1 | import ActionParser from './action'; 2 | import EventParser from './event'; 3 | import { HasuraDataType, HasuraAction, HasuraSessionTypes, HasuraEvent, HasuraEventTrigger, HasuraEventTable, HasuraEventData, HasuraEventPayload, HasuraEventOperationType } from './types'; 4 | export { ActionParser }; 5 | export { EventParser }; 6 | export { HasuraDataType, HasuraAction, HasuraSessionTypes, HasuraEvent, HasuraEventTrigger, HasuraEventTable, HasuraEventData, HasuraEventPayload, HasuraEventOperationType }; 7 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | exports.HasuraEventOperationType = exports.HasuraSessionTypes = exports.HasuraDataType = exports.EventParser = exports.ActionParser = void 0; 7 | var action_1 = __importDefault(require("./action")); 8 | exports.ActionParser = action_1.default; 9 | var event_1 = __importDefault(require("./event")); 10 | exports.EventParser = event_1.default; 11 | var types_1 = require("./types"); 12 | Object.defineProperty(exports, "HasuraDataType", { enumerable: true, get: function () { return types_1.HasuraDataType; } }); 13 | Object.defineProperty(exports, "HasuraSessionTypes", { enumerable: true, get: function () { return types_1.HasuraSessionTypes; } }); 14 | Object.defineProperty(exports, "HasuraEventOperationType", { enumerable: true, get: function () { return types_1.HasuraEventOperationType; } }); 15 | -------------------------------------------------------------------------------- /lib/types.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Hasura Action Event types 3 | */ 4 | declare type HasuraAction = { 5 | session_variables: any; 6 | input: any; 7 | action: HasuraActionData; 8 | }; 9 | declare type HasuraActionData = { 10 | name: string; 11 | }; 12 | /** 13 | * Hasura Event Trigger types 14 | */ 15 | declare type HasuraEvent = { 16 | event: HasuraEventData; 17 | created_at: string; 18 | id: string; 19 | trigger: HasuraEventTrigger; 20 | table: HasuraEventTable; 21 | trace_context: HasuraEventTraceContext; 22 | delivery_info?: HasuraEventDeliveryInfo; 23 | }; 24 | declare type HasuraEventTraceContext = { 25 | trace_id: number; 26 | span_id: number; 27 | }; 28 | declare type HasuraEventDeliveryInfo = { 29 | max_retries: number; 30 | current_retry: number; 31 | }; 32 | declare type HasuraEventTrigger = { 33 | name: string; 34 | }; 35 | declare type HasuraEventTable = { 36 | schema: string; 37 | name: string; 38 | }; 39 | declare type HasuraEventData = { 40 | session_variables: any; 41 | op: HasuraEventOperationType; 42 | data: HasuraEventPayload; 43 | }; 44 | declare type HasuraEventPayload = { 45 | old: any; 46 | new: any; 47 | }; 48 | declare enum HasuraEventOperationType { 49 | UPDATE = "UPDATE", 50 | INSERT = "INSERT", 51 | DELETE = "DELETE", 52 | MANUAL = "MANUAL" 53 | } 54 | declare enum HasuraSessionTypes { 55 | ROLE = "x-hasura-role", 56 | USERID = "x-hasura-user-id" 57 | } 58 | declare enum HasuraDataType { 59 | NEW = "new", 60 | OLD = "old" 61 | } 62 | export { HasuraDataType, HasuraAction, HasuraSessionTypes, HasuraEvent, HasuraEventTrigger, HasuraEventTable, HasuraEventData, HasuraEventPayload, HasuraEventOperationType }; 63 | -------------------------------------------------------------------------------- /lib/types.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.HasuraEventOperationType = exports.HasuraSessionTypes = exports.HasuraDataType = void 0; 4 | var HasuraEventOperationType; 5 | (function (HasuraEventOperationType) { 6 | HasuraEventOperationType["UPDATE"] = "UPDATE"; 7 | HasuraEventOperationType["INSERT"] = "INSERT"; 8 | HasuraEventOperationType["DELETE"] = "DELETE"; 9 | HasuraEventOperationType["MANUAL"] = "MANUAL"; 10 | })(HasuraEventOperationType || (HasuraEventOperationType = {})); 11 | exports.HasuraEventOperationType = HasuraEventOperationType; 12 | var HasuraSessionTypes; 13 | (function (HasuraSessionTypes) { 14 | HasuraSessionTypes["ROLE"] = "x-hasura-role"; 15 | HasuraSessionTypes["USERID"] = "x-hasura-user-id"; 16 | })(HasuraSessionTypes || (HasuraSessionTypes = {})); 17 | exports.HasuraSessionTypes = HasuraSessionTypes; 18 | var HasuraDataType; 19 | (function (HasuraDataType) { 20 | HasuraDataType["NEW"] = "new"; 21 | HasuraDataType["OLD"] = "old"; 22 | })(HasuraDataType || (HasuraDataType = {})); 23 | exports.HasuraDataType = HasuraDataType; 24 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@snotra/hasura-parser", 3 | "version": "1.0.3", 4 | "description": "Parse Hasura actions and events easily.", 5 | "main": "lib/index.js", 6 | "types": "lib/index.d.ts", 7 | "scripts": { 8 | "test": "jest", 9 | "test:coverage": "jest --coverage", 10 | "coverage-badge": "node_modules/lcov-badge/lcov-badge coverage/lcov.info -o badges/coverage.svg", 11 | "build": "tsc", 12 | "prepublish": "tsc && yarn test && yarn coverage-badge", 13 | "prepare": "npm run build", 14 | "start:dev": "tsc -w" 15 | }, 16 | "keywords": [ 17 | "Hasura", 18 | "Hasura Actions", 19 | "Hasura Events", 20 | "Hasura Parser", 21 | "Result", 22 | "Hasura GraphQL" 23 | ], 24 | "author": "Bostjan Cigan (https://bostjan-cigan.com)", 25 | "contributors": [ 26 | { 27 | "name": "Bostjan Cigan " 28 | }, 29 | { 30 | "name": "Marko Divjak " 31 | } 32 | ], 33 | "homepage": "https://snotra.app", 34 | "repository": { 35 | "type": "git", 36 | "url": "https://github.com/snotra-org/hasura-parser.git" 37 | }, 38 | "license": "Apache-2.0", 39 | "dependencies": {}, 40 | "devDependencies": { 41 | "@types/jest": "^26.0.14", 42 | "@types/mocha": "^8.0.3", 43 | "jest": "^26.4.2", 44 | "lcov-badge": "^1.0.4", 45 | "ts-jest": "^26.4.0", 46 | "typescript": "^3.9.5" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/action.ts: -------------------------------------------------------------------------------- 1 | import { 2 | HasuraAction 3 | } from './types' 4 | 5 | class ActionParser { 6 | private payload: HasuraAction 7 | 8 | constructor( payload: HasuraAction ) { 9 | this.payload = payload 10 | } 11 | 12 | /** 13 | * Returns session variable by ID. 14 | * @param id ID of session variable (e.g. x-hasura-user-role). 15 | */ 16 | getSessionVariable( id: string ): string { 17 | return this.payload.session_variables[ id ] 18 | } 19 | 20 | /** 21 | * Returns all session variables. 22 | */ 23 | getSessionVariables(): any { 24 | return this.payload.session_variables 25 | } 26 | 27 | /** 28 | * Returns action name. 29 | */ 30 | getActionName(): string { 31 | return this.payload.action.name 32 | } 33 | 34 | /** 35 | * Gets data from action for provided keys. 36 | * 37 | * @param keys Keys to fetch. 38 | */ 39 | getData( ...keys: Array ): any { 40 | let payload; 41 | 42 | const data: any = {} 43 | 44 | // Some people prefer to do input on mutations and other operations 45 | if ( this.payload.input.input ) { 46 | payload = this.payload.input.input 47 | } else { 48 | payload = this.payload.input 49 | } 50 | 51 | for ( let i = 0; i < keys.length; i++ ) { 52 | const key = keys[ i ] 53 | if ( payload[ key ] ) { 54 | data[ key ] = payload[ key ] 55 | } else { 56 | data[ key ] = null 57 | } 58 | } 59 | 60 | return data 61 | } 62 | 63 | /** 64 | * Returns raw data from payload (not fetching by keys we need.) 65 | */ 66 | getRawData(): any { 67 | if ( this.payload.input.input ) { 68 | return this.payload.input.input 69 | } 70 | return this.payload.input 71 | } 72 | 73 | } 74 | 75 | export default ActionParser -------------------------------------------------------------------------------- /src/event.ts: -------------------------------------------------------------------------------- 1 | import { 2 | HasuraEvent, 3 | HasuraEventOperationType, 4 | HasuraDataType 5 | } from './types' 6 | 7 | class EventParser { 8 | private payload: HasuraEvent 9 | 10 | constructor( payload: HasuraEvent ) { 11 | this.payload = payload 12 | } 13 | 14 | /** 15 | * Returns if operation is an INSERT. 16 | */ 17 | isInsertOperation(): boolean { 18 | return this.getOperationType() === HasuraEventOperationType.INSERT 19 | } 20 | 21 | /** 22 | * Checks if operation is an UPDATE. 23 | */ 24 | isUpdateOperation(): boolean { 25 | return this.getOperationType() === HasuraEventOperationType.UPDATE 26 | } 27 | 28 | /** 29 | * Checks if operation is a DELETE. 30 | */ 31 | isDeleteOperation(): boolean { 32 | return this.getOperationType() === HasuraEventOperationType.DELETE 33 | } 34 | 35 | /** 36 | * Checks if operation is MANUAL. 37 | */ 38 | isManualOperation(): boolean { 39 | return this.getOperationType() === HasuraEventOperationType.MANUAL 40 | } 41 | 42 | /** 43 | * Returns operation type. 44 | */ 45 | getOperationType(): string { 46 | return this.payload.event.op 47 | } 48 | 49 | /** 50 | * Returns session variable by provided ID (e.g. x-hasura-user-role). 51 | * @param id ID of session variable. 52 | */ 53 | getSessionVariable( id: string ): string { 54 | return this.payload.event.session_variables[ id ] 55 | } 56 | 57 | /** 58 | * Returns all session variables. 59 | */ 60 | getSessionVariables(): any { 61 | return this.payload.event.session_variables 62 | } 63 | 64 | /** 65 | * Returns ID of payload. 66 | */ 67 | getID(): string { 68 | return this.payload.id 69 | } 70 | 71 | /** 72 | * Returns trigger name (set in Hasura Console). 73 | */ 74 | getTriggerName(): string { 75 | return this.payload.trigger.name 76 | } 77 | 78 | /** 79 | * Gets schema name that the event affected. 80 | */ 81 | getSchemaName(): string { 82 | return this.payload.table.schema 83 | } 84 | 85 | /** 86 | * Gets table name that the event affected. 87 | */ 88 | getTableName(): string { 89 | return this.payload.table.name 90 | } 91 | 92 | /** 93 | * Returns current retry of the event (if it is set in Hasura Console). 94 | */ 95 | getCurrentRetry(): number | undefined { 96 | return this.payload.delivery_info?.current_retry 97 | } 98 | 99 | /** 100 | * Returns max retries for current event. 101 | */ 102 | getMaxRetries(): number | undefined { 103 | return this.payload.delivery_info?.max_retries 104 | } 105 | 106 | /** 107 | * Returns raw data (old - in UPDATE, DELETE and MANUAL events). 108 | */ 109 | getOldData(): any { 110 | return this.payload.event.data.old 111 | } 112 | 113 | /** 114 | * Returns raw data (new - in INSERT, UPDATE events). 115 | */ 116 | getNewData(): any { 117 | return this.payload.event.data.new 118 | } 119 | 120 | /** 121 | * Returns timestamp of event. 122 | */ 123 | getTimestamp() { 124 | return this.payload.created_at 125 | } 126 | 127 | /** 128 | * Returns trace data - context ID. 129 | */ 130 | getTraceContextID(): number { 131 | return this.payload.trace_context.trace_id 132 | } 133 | 134 | /** 135 | * Returns trace data - span context ID. 136 | */ 137 | getTraceContextSpanID(): number { 138 | return this.payload.trace_context.span_id 139 | } 140 | 141 | private getDataFetchType(): HasuraDataType { 142 | if ( this.isInsertOperation() || this.isManualOperation() ) { 143 | return HasuraDataType.NEW 144 | } 145 | return HasuraDataType.OLD 146 | } 147 | 148 | /** 149 | * Fetches data that was sent by Hasura event by the keys provided. 150 | * 151 | * @param keys Data to fetch. 152 | */ 153 | getData( ...keys: Array ) { 154 | if ( this.isUpdateOperation() ) { 155 | return this.getUData( keys ) 156 | } else { 157 | const type = this.getDataFetchType() 158 | return this.getIDMData( keys, type ) 159 | } 160 | } 161 | 162 | /** 163 | * Fetches update data by keys. If a key does not exist in both new 164 | * and old the value is set to null and an info message is triggered. 165 | * 166 | * @param keys Keys to fetch. 167 | */ 168 | private getUData( keys: Array ) { 169 | const data: any = { 170 | old: {}, 171 | new: {} 172 | } 173 | 174 | for( let i = 0; i < keys.length; i++ ) { 175 | const key = keys[ i ] 176 | if ( this.payload.event.data.old[ key ] && this.payload.event.data.new[ key ] ) { 177 | data.old[ key ] = this.payload.event.data.old[ key ] 178 | data.new[ key ] = this.payload.event.data.new[ key ] 179 | } else { 180 | data.old[ key ] = null 181 | data.new[ key ] = null 182 | } 183 | } 184 | return data 185 | } 186 | 187 | /** 188 | * Fetches data for an INSERT, DELETE or MANUAL operation. 189 | * 190 | * @param keys Keys to fetch. 191 | * @param type Type of operation. 192 | */ 193 | private getIDMData( keys: Array, type: HasuraDataType ): any { 194 | const data: any = {} 195 | 196 | for( let i = 0; i < keys.length; i++ ) { 197 | const key = keys[ i ] 198 | if ( this.payload.event.data[ type ][ key ] ) { 199 | data[ key ] = this.payload.event.data[ type ][ key ] 200 | } else { 201 | data[ key ] = null 202 | } 203 | } 204 | 205 | return data 206 | 207 | } 208 | 209 | } 210 | 211 | export default EventParser -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import ActionParser from './action' 2 | import EventParser from './event' 3 | import { 4 | HasuraDataType, 5 | HasuraAction, 6 | HasuraSessionTypes, 7 | HasuraEvent, 8 | HasuraEventTrigger, 9 | HasuraEventTable, 10 | HasuraEventData, 11 | HasuraEventPayload, 12 | HasuraEventOperationType 13 | } from './types' 14 | 15 | export { ActionParser } 16 | export { EventParser } 17 | 18 | export { 19 | HasuraDataType, 20 | HasuraAction, 21 | HasuraSessionTypes, 22 | HasuraEvent, 23 | HasuraEventTrigger, 24 | HasuraEventTable, 25 | HasuraEventData, 26 | HasuraEventPayload, 27 | HasuraEventOperationType 28 | } -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Hasura Action Event types 3 | */ 4 | type HasuraAction = { 5 | session_variables: any, 6 | input: any, 7 | action: HasuraActionData 8 | } 9 | 10 | type HasuraActionData = { 11 | name: string 12 | } 13 | 14 | /** 15 | * Hasura Event Trigger types 16 | */ 17 | 18 | type HasuraEvent = { 19 | event: HasuraEventData, 20 | created_at: string, 21 | id: string, 22 | trigger: HasuraEventTrigger, 23 | table: HasuraEventTable, 24 | trace_context: HasuraEventTraceContext 25 | delivery_info?: HasuraEventDeliveryInfo 26 | } 27 | 28 | type HasuraEventTraceContext = { 29 | trace_id: number, 30 | span_id: number 31 | } 32 | 33 | type HasuraEventDeliveryInfo = { 34 | max_retries: number, 35 | current_retry: number 36 | } 37 | 38 | type HasuraEventTrigger = { 39 | name: string 40 | } 41 | 42 | type HasuraEventTable = { 43 | schema: string, 44 | name: string 45 | } 46 | 47 | type HasuraEventData = { 48 | session_variables: any, 49 | op: HasuraEventOperationType, 50 | data: HasuraEventPayload 51 | } 52 | 53 | type HasuraEventPayload = { 54 | old: any, 55 | new: any 56 | } 57 | 58 | enum HasuraEventOperationType { 59 | UPDATE = "UPDATE", 60 | INSERT = "INSERT", 61 | DELETE = "DELETE", 62 | MANUAL = "MANUAL" 63 | } 64 | 65 | enum HasuraSessionTypes { 66 | ROLE = "x-hasura-role", 67 | USERID = "x-hasura-user-id" 68 | } 69 | 70 | enum HasuraDataType { 71 | NEW = "new", 72 | OLD = "old" 73 | } 74 | 75 | export { 76 | HasuraDataType, 77 | HasuraAction, 78 | HasuraSessionTypes, 79 | HasuraEvent, 80 | HasuraEventTrigger, 81 | HasuraEventTable, 82 | HasuraEventData, 83 | HasuraEventPayload, 84 | HasuraEventOperationType 85 | } -------------------------------------------------------------------------------- /tests/action.test.ts: -------------------------------------------------------------------------------- 1 | import ActionParser from '../src/action' 2 | import { HasuraAction } from '../src/types' 3 | 4 | const testData = { 5 | parse: { 6 | session_variables: { 7 | 'x-hasura-user-id': '5' 8 | }, 9 | input: {}, 10 | action: { 11 | name: 'test-action' 12 | } 13 | }, 14 | data: { 15 | session_variables: { 16 | 'x-hasura-user-id': '5' 17 | }, 18 | input: { 19 | input: { 20 | 'id': 5, 21 | 'data': 'test' 22 | } 23 | }, 24 | action: { 25 | name: 'test-action' 26 | } 27 | }, 28 | dataInput: { 29 | session_variables: { 30 | 'x-hasura-user-id': '5' 31 | }, 32 | input: { 33 | 'id': 5, 34 | 'data': 'test' 35 | }, 36 | action: { 37 | name: 'test-action' 38 | } 39 | } 40 | } 41 | 42 | describe( 'General parsing', () => { 43 | it( 'Action name', () => { 44 | const payload: HasuraAction = testData.parse 45 | let parser = new ActionParser( payload ) 46 | expect( parser.getActionName() ).toBe( 'test-action' ) 47 | } ) 48 | }) 49 | 50 | describe( 'Data fetching', () => { 51 | it( 'With input argument', () => { 52 | const payload: HasuraAction = testData.data 53 | let parser = new ActionParser( payload ) 54 | const data = parser.getData( "id", "data", "type" ) 55 | expect( data.id ).toBe( payload.input.input.id ) 56 | expect( data.data ).toBe( payload.input.input.data ) 57 | expect( data.type ).toBe( null ) 58 | } ) 59 | it( 'Without input argument', () => { 60 | const payload: HasuraAction = testData.dataInput 61 | let parser = new ActionParser( payload ) 62 | const data = parser.getData( "id", "data", "type" ) 63 | expect( data.id ).toBe( payload.input.id ) 64 | expect( data.data ).toBe( payload.input.data ) 65 | expect( data.type ).toBe( null ) 66 | } ) 67 | it( 'Raw data', () => { 68 | const payload: HasuraAction = testData.dataInput 69 | let parser = new ActionParser( payload ) 70 | const data = parser.getRawData() 71 | expect( data ).toBe( payload.input ) 72 | } ) 73 | it( 'Raw data with input argument', () => { 74 | const payload: HasuraAction = testData.data 75 | let parser = new ActionParser( payload ) 76 | const data = parser.getRawData() 77 | expect( data ).toBe( payload.input.input ) 78 | } ) 79 | }) 80 | 81 | describe( 'Session variables', () => { 82 | it( 'User ID', () => { 83 | const payload: HasuraAction = testData.parse 84 | let parser = new ActionParser( payload ) 85 | expect( parser.getSessionVariable( 'x-hasura-user-id' ) ).toBe( testData.parse.session_variables["x-hasura-user-id"] ) 86 | expect( parser.getSessionVariable( 'no-variable' ) ).toBe( undefined ) 87 | } ) 88 | it( 'All values', () => { 89 | const payload: HasuraAction = testData.parse 90 | let parser = new ActionParser( payload ) 91 | expect( parser.getSessionVariables() ).toBe( testData.parse.session_variables ) 92 | } ) 93 | }) 94 | 95 | -------------------------------------------------------------------------------- /tests/event.test.ts: -------------------------------------------------------------------------------- 1 | import EventParser from '../src/event' 2 | import { HasuraEvent, HasuraEventOperationType } from '../src/types' 3 | 4 | const testData = { 5 | parse: { 6 | event: { 7 | session_variables: { 8 | 'x-hasura-user-id': 5, 9 | 'x-hasura-user-role': 'admin' 10 | }, 11 | op: HasuraEventOperationType.MANUAL, 12 | data: { 13 | old: null, 14 | new: null 15 | } 16 | }, 17 | created_at: "0", 18 | id: "5", 19 | trigger: { 20 | name: "trigger" 21 | }, 22 | table: { 23 | schema: "public", 24 | name: "user" 25 | }, 26 | trace_context: { 27 | trace_id: 3, 28 | span_id: 5 29 | }, 30 | delivery_info: { 31 | max_retries: 0, 32 | current_retry: 0 33 | } 34 | }, 35 | delivery_info: { 36 | event: { 37 | session_variables: { 38 | 'x-hasura-user-id': 5, 39 | 'x-hasura-user-role': 'admin' 40 | }, 41 | op: HasuraEventOperationType.MANUAL, 42 | data: { 43 | old: null, 44 | new: null 45 | } 46 | }, 47 | created_at: "0", 48 | id: "5", 49 | trigger: { 50 | name: "trigger" 51 | }, 52 | table: { 53 | schema: "public", 54 | name: "user" 55 | }, 56 | trace_context: { 57 | trace_id: 3, 58 | span_id: 5 59 | } 60 | }, 61 | insert: { 62 | event: { 63 | session_variables: {}, 64 | op: HasuraEventOperationType.INSERT, 65 | data: { 66 | old: null, 67 | new: { 68 | 'id': 3, 69 | 'name': 'bostjan' 70 | } 71 | } 72 | }, 73 | created_at: "", 74 | id: "", 75 | trigger: { 76 | name: "trigger" 77 | }, 78 | table: { 79 | schema: "public", 80 | name: "user" 81 | }, 82 | trace_context: { 83 | trace_id: 3, 84 | span_id: 5 85 | }, 86 | delivery_info: { 87 | max_retries: 0, 88 | current_retry: 0 89 | } 90 | }, 91 | update: { 92 | event: { 93 | session_variables: {}, 94 | op: HasuraEventOperationType.UPDATE, 95 | data: { 96 | old: { 97 | 'id': 5, 98 | 'name': 'victor' 99 | }, 100 | new: { 101 | 'id': 3, 102 | 'name': 'bostjan' 103 | } 104 | } 105 | }, 106 | created_at: "", 107 | id: "", 108 | trigger: { 109 | name: "trigger" 110 | }, 111 | table: { 112 | schema: "public", 113 | name: "user" 114 | }, 115 | trace_context: { 116 | trace_id: 3, 117 | span_id: 5 118 | }, 119 | delivery_info: { 120 | max_retries: 0, 121 | current_retry: 0 122 | } 123 | }, 124 | delete: { 125 | event: { 126 | session_variables: {}, 127 | op: HasuraEventOperationType.DELETE, 128 | data: { 129 | old: { 130 | 'id': 5, 131 | 'name': 'victor' 132 | }, 133 | new: { 134 | 'id': 3, 135 | 'name': 'bostjan' 136 | } 137 | } 138 | }, 139 | created_at: "", 140 | id: "", 141 | trigger: { 142 | name: "trigger" 143 | }, 144 | table: { 145 | schema: "public", 146 | name: "user" 147 | }, 148 | trace_context: { 149 | trace_id: 3, 150 | span_id: 5 151 | }, 152 | delivery_info: { 153 | max_retries: 0, 154 | current_retry: 0 155 | } 156 | }, 157 | manual: { 158 | event: { 159 | session_variables: {}, 160 | op: HasuraEventOperationType.MANUAL, 161 | data: { 162 | old: { 163 | 'id': 5, 164 | 'name': 'victor' 165 | }, 166 | new: { 167 | 'id': 3, 168 | 'name': 'bostjan' 169 | } 170 | } 171 | }, 172 | created_at: "", 173 | id: "", 174 | trigger: { 175 | name: "trigger" 176 | }, 177 | table: { 178 | schema: "public", 179 | name: "user" 180 | }, 181 | trace_context: { 182 | trace_id: 3, 183 | span_id: 5 184 | }, 185 | delivery_info: { 186 | max_retries: 0, 187 | current_retry: 0 188 | } 189 | } 190 | } 191 | 192 | describe( 'General parsing', () => { 193 | it( 'Operation type', () => { 194 | const payload: HasuraEvent = testData.parse 195 | let parser = new EventParser( payload ) 196 | expect( parser.getOperationType() ).toBe( "MANUAL" ) 197 | } ) 198 | it( 'ID', () => { 199 | const payload: HasuraEvent = testData.parse 200 | let parser = new EventParser( payload ) 201 | expect( parser.getID() ).toBe( "5" ) 202 | } ) 203 | it( 'Trigger name', () => { 204 | const payload: HasuraEvent = testData.parse 205 | let parser = new EventParser( payload ) 206 | expect( parser.getTriggerName() ).toBe( "trigger" ) 207 | } ) 208 | it( 'Schema name', () => { 209 | const payload: HasuraEvent = testData.parse 210 | let parser = new EventParser( payload ) 211 | expect( parser.getSchemaName() ).toBe( "public" ) 212 | } ) 213 | it( 'Table name', () => { 214 | const payload: HasuraEvent = testData.parse 215 | let parser = new EventParser( payload ) 216 | expect( parser.getTableName() ).toBe( "user" ) 217 | } ) 218 | it( 'Current retry', () => { 219 | const payload: HasuraEvent = testData.parse 220 | let parser = new EventParser( payload ) 221 | expect( parser.getCurrentRetry() ).toBe( 0 ) 222 | } ) 223 | it( 'Max retries', () => { 224 | const payload: HasuraEvent = testData.parse 225 | let parser = new EventParser( payload ) 226 | expect( parser.getMaxRetries() ).toBe( 0 ) 227 | } ) 228 | it( 'Timestamp', () => { 229 | const payload: HasuraEvent = testData.parse 230 | let parser = new EventParser( payload ) 231 | expect( parser.getTimestamp() ).toBe( "0" ) 232 | } ) 233 | it( 'Trace context ID', () => { 234 | const payload: HasuraEvent = testData.parse 235 | let parser = new EventParser( payload ) 236 | expect( parser.getTraceContextID() ).toBe( 3 ) 237 | } ) 238 | it( 'Trace context span ID', () => { 239 | const payload: HasuraEvent = testData.parse 240 | let parser = new EventParser( payload ) 241 | expect( parser.getTraceContextSpanID() ).toBe( 5 ) 242 | } ), 243 | it( 'Session variables', () => { 244 | const payload: HasuraEvent = testData.parse 245 | let parser = new EventParser( payload ) 246 | expect( parser.getSessionVariables() ).toBe( payload.event.session_variables ) 247 | } ) 248 | it( 'OLD data', () => { 249 | const payload: HasuraEvent = testData.parse 250 | let parser = new EventParser( payload ) 251 | expect( parser.getOldData() ).toBe( null ) 252 | } ) 253 | it( 'NEW data', () => { 254 | const payload: HasuraEvent = testData.parse 255 | let parser = new EventParser( payload ) 256 | expect( parser.getNewData() ).toBe( null ) 257 | } ) 258 | }) 259 | 260 | describe( 'Delivery info', () => { 261 | it( 'Delivery info', () => { 262 | const payload: HasuraEvent = testData.delivery_info 263 | let parser = new EventParser( payload ) 264 | expect( parser.getMaxRetries() ).toBe( undefined ) 265 | expect( parser.getCurrentRetry() ).toBe( undefined ) 266 | } ) 267 | }) 268 | 269 | describe( 'Session variables', () => { 270 | it( 'User ID, user role, user session', () => { 271 | const payload: HasuraEvent = testData.parse 272 | let parser = new EventParser( payload ) 273 | expect( parser.getSessionVariable( 'x-hasura-user-id' ) ).toBe( 5 ) 274 | expect( parser.getSessionVariable( 'x-hasura-user-role' ) ).toBe( 'admin' ) 275 | expect( parser.getSessionVariable( 'x-hasura-user-session' ) ).toBe( undefined ) 276 | } ) 277 | }) 278 | 279 | describe( 'Insert Operation', () => { 280 | it( 'Fetching insert data', () => { 281 | const payload: HasuraEvent = testData.insert 282 | const parser = new EventParser( payload ) 283 | const data = parser.getData( "id", "name", "type" ) 284 | expect( data.id ).toBe( payload.event.data.new.id ) 285 | expect( data.name ).toBe( payload.event.data.new.name ) 286 | expect( data.type ).toBe( null ) 287 | } ) 288 | it( 'Checking Fetching insert data', () => { 289 | const payload: HasuraEvent = testData.insert 290 | const parser = new EventParser( payload ) 291 | const data = parser.getData( "id", "name", "type" ) 292 | expect( data.id ).toBe( payload.event.data.new.id ) 293 | expect( data.name ).toBe( payload.event.data.new.name ) 294 | expect( data.type ).toBe( null ) 295 | } ) 296 | } ) 297 | 298 | describe( 'Update Operation', () => { 299 | it( 'Checking update data', () => { 300 | const payload: HasuraEvent = testData.update 301 | const parser = new EventParser( payload ) 302 | const data = parser.getData( "id", "type" ) 303 | expect( data.old.id ).toBe( payload.event.data.old.id ) 304 | expect( data.new.id ).toBe( payload.event.data.new.id ) 305 | expect( data.old.type ).toBe( null ) 306 | expect( data.new.type ).toBe( null ) 307 | } ) 308 | } ) 309 | 310 | describe( 'Delete Operation', () => { 311 | it( 'Checking delete data', () => { 312 | const payload: HasuraEvent = testData.delete 313 | const parser = new EventParser( payload ) 314 | const data = parser.getData( "id", "type" ) 315 | expect( data.id ).toBe( payload.event.data.old.id ) 316 | } ) 317 | it( 'Checking OP type', () => { 318 | const payload: HasuraEvent = testData.delete 319 | const parser = new EventParser( payload ) 320 | expect( parser.isDeleteOperation() ).toBe( true ) 321 | } ) 322 | } ) 323 | 324 | describe( 'Manual Operation', () => { 325 | it( 'Checking manual data', () => { 326 | const payload: HasuraEvent = testData.manual 327 | const parser = new EventParser( payload ) 328 | const data = parser.getData( "id", "type" ) 329 | expect( data.id ).toBe( payload.event.data.new.id ) 330 | } ) 331 | it( 'Checking OP type', () => { 332 | const payload: HasuraEvent = testData.manual 333 | const parser = new EventParser( payload ) 334 | expect( parser.isManualOperation() ).toBe( true ) 335 | } ) 336 | } ) -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig.json to read more about this file */ 4 | 5 | /* Basic Options */ 6 | // "incremental": true, /* Enable incremental compilation */ 7 | "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ 8 | "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ 9 | "lib": [ "es2015", "dom" ], /* Specify library files to be included in the compilation. */ 10 | // "allowJs": true, /* Allow javascript files to be compiled. */ 11 | // "checkJs": true, /* Report errors in .js files. */ 12 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ 13 | "declaration": true, /* Generates corresponding '.d.ts' file. */ 14 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ 15 | // "sourceMap": true, /* Generates corresponding '.map' file. */ 16 | // "outFile": "./", /* Concatenate and emit output to single file. */ 17 | "outDir": "lib", /* Redirect output structure to the directory. */ 18 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 19 | // "composite": true, /* Enable project compilation */ 20 | // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ 21 | // "removeComments": true, /* Do not emit comments to output. */ 22 | // "noEmit": true, /* Do not emit outputs. */ 23 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 24 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 25 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 26 | 27 | /* Strict Type-Checking Options */ 28 | "strict": true, /* Enable all strict type-checking options. */ 29 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ 30 | // "strictNullChecks": true, /* Enable strict null checks. */ 31 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */ 32 | // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ 33 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ 34 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ 35 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ 36 | 37 | /* Additional Checks */ 38 | // "noUnusedLocals": true, /* Report errors on unused locals. */ 39 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 40 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 41 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 42 | 43 | /* Module Resolution Options */ 44 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 45 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 46 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 47 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 48 | // "typeRoots": [], /* List of folders to include type definitions from. */ 49 | "typeRoots": [ "./types", "./node_modules/@types" ], 50 | // "types": [], /* Type declaration files to be included in compilation. */ 51 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 52 | "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 53 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 54 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 55 | 56 | /* Source Map Options */ 57 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 58 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 59 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 60 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 61 | 62 | /* Experimental Options */ 63 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 64 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 65 | 66 | /* Advanced Options */ 67 | "skipLibCheck": true, /* Skip type checking of declaration files. */ 68 | "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ 69 | }, 70 | "exclude": [ 71 | "tests/", 72 | "**/*.d.ts" 73 | ] 74 | } 75 | --------------------------------------------------------------------------------