README.md (3710B)
1 query-engine.ts 2 =============== 3 4 Intended usage: 5 6 ```ts 7 8 9 // model/user.ts 10 11 import { Document, ID, Version, String, Index, CompositeIndex } from '@finwo/query-engine/decorators'; 12 13 @Document({ adapter?: customAdapterInstance }) 14 @CompositeIndex('otherIndexName', { 15 fields: ['fieldA', 'fieldB'] 16 order?: 'ascending', 17 unique?: true/false, 18 }) 19 export class User { 20 21 @Version() 22 static _version = 0; 23 24 static _migrate(record: Record<??>): User { 25 // Code to update old version to current 26 } 27 28 // TODO: define proper annotations 29 @ID() 30 _id: string; 31 32 @String() 33 @Index('indexName'[, { order?: 'ascending', unique?: true/false }]) 34 username: string; 35 36 ... 37 } 38 39 // main.ts 40 import QueryEngine from '@finwo/query-engine'; 41 42 import { LevelAdapter } from '@finwo/query-engine'; 43 44 import { User } from 'model/user.ts'; 45 46 const queryEngine = new QueryEngine({ 47 defaultAdapter: new LevelAdapter({ 48 datadir: __dirname + '/data/' 49 }), 50 documents: { 51 documentTypeName: { 52 model: User, 53 } 54 }, 55 }); 56 57 // Runtime addition: 58 queryEngine.defineTable(...) 59 queryEngine.registerAdapter('name', adapterInstance) 60 61 const data = await queryEngine 62 63 // Start query builder 64 .query('documentTypeName') 65 66 // Initial result set 67 .useIndex('indexName', { 68 strategy: 'merge-strategy TBD: outer (keep both), inner (keep overlap), union, etc....', 69 filter: { 70 fieldName: { 71 operator: 'lte, gte, ...', 72 value: 'some-value', 73 } 74 } 75 }) 76 77 // Future feature 78 // Define symbol to search without running through user-code 79 .defineSymbol('symbolName', 'fieldName') 80 81 // Filter down further 82 .useIndex('otherIndex', { 83 strategy: 'inner', 84 filter: { 85 otherField: { 86 operator: 'in', 87 symbol: 'symbolName', 88 } 89 } 90 }) 91 92 // TODO: how to do joins and merges with other document types? 93 94 // And start the query, returns promise to the data 95 .values(); 96 97 // Inserting documents 98 await queryEngine 99 .insert('documentTypeName', entity instanceof User?, { 100 upsert: false, // Throw error if already exists, default 101 upsert: true, // Quietly overwrite if already exists 102 }) 103 .insert('documentTypeName', ...) 104 105 // Updating single document 106 await queryEngine 107 .update('documentTypeName', 'documentId', { 108 ..newData 109 }); 110 111 // Updating multiple documents, fixed value 112 await queryEngine 113 .query('documentTypeName') 114 .useIndex(...) 115 .update({ 116 ...newData 117 }); 118 119 // Updating multiple documents, dynamic value 120 await queryEngine 121 .query('documentTypeName') 122 .useIndex(...) 123 .update(document => { 124 // Do some actions here 125 document.profit = document.income - document.costs; 126 return document; // <-- something else maybe? 127 }); 128 129 // Deleting documents by _id 130 await queryEngine 131 .delete('documentTypeName', 'documentId'); 132 133 // Deleting documents by query 134 await queryEngine 135 .query('documentTypeName') 136 .useIndex(...) 137 .delete() 138 139 ``` 140 141 On-disk/storage, per table, we get something like: 142 143 ``` 144 145 /cfg 146 { 147 indexes: { 148 _id: { 149 fields: ['_id'], 150 order: 'ascending', 151 unique: true, 152 }, 153 indexName: { 154 fields: ['username'], 155 order: 'ascending', 156 unique: true, 157 }, 158 } 159 // more to be defined 160 } 161 162 /idx/<indexName>/<hex-encoded-value> 163 <documentId> 164 <documentId> 165 ... 166 167 /obj/<hex-encoded-object-id> 168 { 169 _id: <uuid>, 170 _version: 123, 171 username: 'alice' 172 }, 173 174 ```