Implement LazyArray.splice(), implement unshift/shift/push/pop in terms of splice...
[logjson.git] / Transaction.mjs
1 import assert from 'assert'
2 import fsPromises from 'fs/promises'
3 import Database from './Database.mjs'
4 import LazyValue from './LazyValue.mjs'
5 import LazyArray from './LazyArray.mjs'
6 import LazyObject from './LazyObject.mjs'
7 import logjson from './index.mjs'
8
9 class Transaction {
10   constructor(database, value) {
11     assert(database instanceof Database)
12     this.database = database
13     this.dirty = false
14     this.value = value
15   }
16
17   async read(ptr_len) {
18     let value = await this.database.read(ptr_len)
19     assert(typeof value === 'object' && value !== null)
20     return (
21       value instanceof Array ?
22         new LazyArray(this, ptr_len, value) :
23         new LazyObject(this, ptr_len, value)
24     )
25   }
26
27   async get(default_value) {
28     if (this.value === undefined) {
29       if (default_value === undefined)
30         return undefined
31       this.set(this.json_to_logjson(default_value))
32     }
33
34     if (this.value instanceof Array)
35       this.value = await this.read(this.value)
36     return this.value
37   }
38
39   async get_json(default_value) {
40     return /*await*/ logjson.logjson_to_json(
41       await this.get(default_value)
42     )
43   }
44
45   set(value) {
46     this.dirty = true
47     assert(
48       typeof value !== 'object' ||
49       value === null ||
50       (value instanceof LazyValue && value.transaction === this)
51     )
52     this.value = value
53   }
54
55   set_json(value) {
56     this.set(this.json_to_logjson(value))
57   }
58
59   async commit() {
60     //console.log('commit transaction', this.serial)
61     assert(this.value !== undefined)
62
63     if (this.value instanceof LazyValue) {
64       if (await this.value.commit())
65         this.dirty = true
66       this.value = this.value.ptr_len
67     }
68
69     if (this.dirty) {
70       await this.database.write_root(this.value)
71       this.database.value = this.value
72     }
73
74     if (this.database.write_list_len && this.database.write_count === 0) {
75       if (this.database.write_timeout === 0)
76         await this.database.flush()
77       else
78         this.database.write_count = this.database.write_timeout
79     }
80
81     this.database.mutex.release()
82   }
83
84   rollback() {
85     //console.log('rollback transaction', this.serial)
86     this.database.mutex.release()
87   }
88
89   LazyArray(...args) {
90     return new LazyArray(this, null, ...args)
91   }
92
93   LazyObject(...args) {
94     return new LazyObject(this, null, ...args)
95   }
96
97   json_to_logjson(value) {
98     if (typeof value === 'object' && value !== null) {
99       let new_value
100       if (value instanceof Array) {
101         new_value = new LazyArray(this)
102         for (let i = 0; i < value.length; ++i)
103           new_value.push(this.json_to_logjson(value[i]))
104       }
105       else {
106         new_value = new LazyObject(this)
107         for (let i in value)
108           new_value.set(i, this.json_to_logjson(value[i]))
109       }
110       value = new_value
111     }
112     return value
113   }
114 }
115
116 export default Transaction