@electric-sql/client 0.3.2 → 0.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.cjs +24 -10
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/index.browser.mjs +1 -1
- package/dist/index.browser.mjs.map +1 -1
- package/dist/index.d.ts +45 -46
- package/dist/index.legacy-esm.js +24 -10
- package/dist/index.legacy-esm.js.map +1 -1
- package/dist/index.mjs +24 -10
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/client.ts +49 -43
- package/src/helpers.ts +3 -3
- package/src/parser.ts +43 -25
- package/src/types.ts +5 -5
package/src/helpers.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ChangeMessage, ControlMessage, Message,
|
|
1
|
+
import { ChangeMessage, ControlMessage, Message, Row } from './types'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Type guard for checking {@link Message} is {@link ChangeMessage}.
|
|
@@ -17,7 +17,7 @@ import { ChangeMessage, ControlMessage, Message, Value } from './types'
|
|
|
17
17
|
* }
|
|
18
18
|
* ```
|
|
19
19
|
*/
|
|
20
|
-
export function isChangeMessage<T extends
|
|
20
|
+
export function isChangeMessage<T extends Row = Row>(
|
|
21
21
|
message: Message<T>
|
|
22
22
|
): message is ChangeMessage<T> {
|
|
23
23
|
return `key` in message
|
|
@@ -40,7 +40,7 @@ export function isChangeMessage<T extends Value = { [key: string]: Value }>(
|
|
|
40
40
|
* }
|
|
41
41
|
* ```
|
|
42
42
|
*/
|
|
43
|
-
export function isControlMessage<T extends
|
|
43
|
+
export function isControlMessage<T extends Row = Row>(
|
|
44
44
|
message: Message<T>
|
|
45
45
|
): message is ControlMessage {
|
|
46
46
|
return !isChangeMessage(message)
|
package/src/parser.ts
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
|
-
import { ColumnInfo, Message, Schema, Value } from './types'
|
|
1
|
+
import { ColumnInfo, Message, Row, Schema, Value } from './types'
|
|
2
2
|
|
|
3
|
+
type NullToken = null | `NULL`
|
|
4
|
+
type Token = Exclude<string, NullToken>
|
|
5
|
+
type NullableToken = Token | NullToken
|
|
3
6
|
export type ParseFunction = (
|
|
4
|
-
value:
|
|
7
|
+
value: Token,
|
|
8
|
+
additionalInfo?: Omit<ColumnInfo, `type` | `dims`>
|
|
9
|
+
) => Value
|
|
10
|
+
type NullableParseFunction = (
|
|
11
|
+
value: NullableToken,
|
|
5
12
|
additionalInfo?: Omit<ColumnInfo, `type` | `dims`>
|
|
6
13
|
) => Value
|
|
7
14
|
export type Parser = { [key: string]: ParseFunction }
|
|
@@ -10,6 +17,7 @@ const parseNumber = (value: string) => Number(value)
|
|
|
10
17
|
const parseBool = (value: string) => value === `true` || value === `t`
|
|
11
18
|
const parseBigInt = (value: string) => BigInt(value)
|
|
12
19
|
const parseJson = (value: string) => JSON.parse(value)
|
|
20
|
+
const identityParser: ParseFunction = (v: string) => v
|
|
13
21
|
|
|
14
22
|
export const defaultParser: Parser = {
|
|
15
23
|
int2: parseNumber,
|
|
@@ -23,10 +31,7 @@ export const defaultParser: Parser = {
|
|
|
23
31
|
}
|
|
24
32
|
|
|
25
33
|
// Taken from: https://github.com/electric-sql/pglite/blob/main/packages/pglite/src/types.ts#L233-L279
|
|
26
|
-
export function pgArrayParser(
|
|
27
|
-
value: string,
|
|
28
|
-
parser?: (s: string) => Value
|
|
29
|
-
): Value {
|
|
34
|
+
export function pgArrayParser(value: Token, parser?: ParseFunction): Value {
|
|
30
35
|
let i = 0
|
|
31
36
|
let char = null
|
|
32
37
|
let str = ``
|
|
@@ -74,7 +79,7 @@ export function pgArrayParser(
|
|
|
74
79
|
return loop(value)[0]
|
|
75
80
|
}
|
|
76
81
|
|
|
77
|
-
export class MessageParser {
|
|
82
|
+
export class MessageParser<T extends Row> {
|
|
78
83
|
private parser: Parser
|
|
79
84
|
constructor(parser?: Parser) {
|
|
80
85
|
// Merge the provided parser with the default parser
|
|
@@ -83,7 +88,7 @@ export class MessageParser {
|
|
|
83
88
|
this.parser = { ...defaultParser, ...parser }
|
|
84
89
|
}
|
|
85
90
|
|
|
86
|
-
parse(messages: string, schema: Schema): Message[] {
|
|
91
|
+
parse(messages: string, schema: Schema): Message<T>[] {
|
|
87
92
|
return JSON.parse(messages, (key, value) => {
|
|
88
93
|
// typeof value === `object` is needed because
|
|
89
94
|
// there could be a column named `value`
|
|
@@ -92,15 +97,15 @@ export class MessageParser {
|
|
|
92
97
|
// Parse the row values
|
|
93
98
|
const row = value as Record<string, Value>
|
|
94
99
|
Object.keys(row).forEach((key) => {
|
|
95
|
-
row[key] = this.parseRow(key, row[key] as
|
|
100
|
+
row[key] = this.parseRow(key, row[key] as NullableToken, schema)
|
|
96
101
|
})
|
|
97
102
|
}
|
|
98
103
|
return value
|
|
99
|
-
}) as Message[]
|
|
104
|
+
}) as Message<T>[]
|
|
100
105
|
}
|
|
101
106
|
|
|
102
107
|
// Parses the message values using the provided parser based on the schema information
|
|
103
|
-
private parseRow(key: string, value:
|
|
108
|
+
private parseRow(key: string, value: NullableToken, schema: Schema): Value {
|
|
104
109
|
const columnInfo = schema[key]
|
|
105
110
|
if (!columnInfo) {
|
|
106
111
|
// We don't have information about the value
|
|
@@ -114,13 +119,17 @@ export class MessageParser {
|
|
|
114
119
|
// Pick the right parser for the type
|
|
115
120
|
// and support parsing null values if needed
|
|
116
121
|
// if no parser is provided for the given type, just return the value as is
|
|
117
|
-
const
|
|
118
|
-
const
|
|
119
|
-
const parser = makeNullableParser(typParser, columnInfo.not_null)
|
|
122
|
+
const typeParser = this.parser[typ] ?? identityParser
|
|
123
|
+
const parser = makeNullableParser(typeParser, columnInfo, key)
|
|
120
124
|
|
|
121
125
|
if (dimensions && dimensions > 0) {
|
|
122
126
|
// It's an array
|
|
123
|
-
|
|
127
|
+
const nullablePgArrayParser = makeNullableParser(
|
|
128
|
+
(value, _) => pgArrayParser(value, parser),
|
|
129
|
+
columnInfo,
|
|
130
|
+
key
|
|
131
|
+
)
|
|
132
|
+
return nullablePgArrayParser(value)
|
|
124
133
|
}
|
|
125
134
|
|
|
126
135
|
return parser(value, additionalInfo)
|
|
@@ -129,15 +138,24 @@ export class MessageParser {
|
|
|
129
138
|
|
|
130
139
|
function makeNullableParser(
|
|
131
140
|
parser: ParseFunction,
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
+
columnInfo: ColumnInfo,
|
|
142
|
+
columnName?: string
|
|
143
|
+
): NullableParseFunction {
|
|
144
|
+
const isNullable = !(columnInfo.not_null ?? false)
|
|
145
|
+
// The sync service contains `null` value for a column whose value is NULL
|
|
146
|
+
// but if the column value is an array that contains a NULL value
|
|
147
|
+
// then it will be included in the array string as `NULL`, e.g.: `"{1,NULL,3}"`
|
|
148
|
+
return (value: NullableToken) => {
|
|
149
|
+
if (isPgNull(value)) {
|
|
150
|
+
if (!isNullable) {
|
|
151
|
+
throw new Error(`Column ${columnName ?? `unknown`} is not nullable`)
|
|
152
|
+
}
|
|
153
|
+
return null
|
|
154
|
+
}
|
|
155
|
+
return parser(value, columnInfo)
|
|
141
156
|
}
|
|
142
|
-
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function isPgNull(value: NullableToken): value is NullToken {
|
|
160
|
+
return value === null || value === `NULL`
|
|
143
161
|
}
|
package/src/types.ts
CHANGED
|
@@ -7,6 +7,8 @@ export type Value =
|
|
|
7
7
|
| Value[]
|
|
8
8
|
| { [key: string]: Value }
|
|
9
9
|
|
|
10
|
+
export type Row = { [key: string]: Value }
|
|
11
|
+
|
|
10
12
|
export type Offset = `-1` | `${number}_${number}`
|
|
11
13
|
|
|
12
14
|
interface Header {
|
|
@@ -17,7 +19,7 @@ export type ControlMessage = {
|
|
|
17
19
|
headers: Header & { control: `up-to-date` | `must-refetch` }
|
|
18
20
|
}
|
|
19
21
|
|
|
20
|
-
export type ChangeMessage<T> = {
|
|
22
|
+
export type ChangeMessage<T extends Row = Row> = {
|
|
21
23
|
key: string
|
|
22
24
|
value: T
|
|
23
25
|
headers: Header & { operation: `insert` | `update` | `delete` }
|
|
@@ -25,9 +27,7 @@ export type ChangeMessage<T> = {
|
|
|
25
27
|
}
|
|
26
28
|
|
|
27
29
|
// Define the type for a record
|
|
28
|
-
export type Message<T extends
|
|
29
|
-
| ControlMessage
|
|
30
|
-
| ChangeMessage<T>
|
|
30
|
+
export type Message<T extends Row = Row> = ControlMessage | ChangeMessage<T>
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
33
|
* Common properties for all columns.
|
|
@@ -104,7 +104,7 @@ export type ColumnInfo =
|
|
|
104
104
|
|
|
105
105
|
export type Schema = { [key: string]: ColumnInfo }
|
|
106
106
|
|
|
107
|
-
export type TypedMessages<T extends
|
|
107
|
+
export type TypedMessages<T extends Row = Row> = {
|
|
108
108
|
messages: Array<Message<T>>
|
|
109
109
|
schema: ColumnInfo
|
|
110
110
|
}
|