Skip to content

Commit 528c657

Browse files
feat: extend bigint support in database table components
- Added bigint type to the Columns type definition. - Updated bigint input handling in the bigint.svelte component, replacing InputText with InputNumber for better user experience. - Enhanced data binding and validation for bigint values, including min, max, and default settings. - Adjusted column value handling in various components to accommodate bigint type.
1 parent 272f2e9 commit 528c657

4 files changed

Lines changed: 48 additions & 126 deletions

File tree

src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/bigint.svelte

Lines changed: 38 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@
4242

4343
<script lang="ts">
4444
import { Layout } from '@appwrite.io/pink-svelte';
45-
import { InputText } from '$lib/elements/forms';
45+
import { InputNumber } from '$lib/elements/forms';
46+
import { createConservative } from '$lib/helpers/stores';
4647
import RequiredArrayCheckboxes from './requiredArrayCheckboxes.svelte';
4748
4849
type Props = {
@@ -54,127 +55,68 @@
5455
let {
5556
editing = false,
5657
disabled = false,
57-
data = $bindable({ required: false, array: false })
58+
data = $bindable({
59+
required: false,
60+
min: 0,
61+
max: 0,
62+
default: 0,
63+
array: false
64+
})
5865
}: Props = $props();
5966
6067
let savedDefault = data.default;
61-
let minString = $state(data.min?.toString() ?? '');
62-
let maxString = $state(data.max?.toString() ?? '');
63-
let defaultString = $state(data.default?.toString() ?? '');
6468
65-
let minError = $state<string | null>(null);
66-
let maxError = $state<string | null>(null);
67-
let defaultError = $state<string | null>(null);
68-
69-
let prevHideDefault = $state<boolean | null>(null);
70-
let lastWrittenMin: Models.ColumnBigint['min'] = undefined;
71-
let lastWrittenMax: Models.ColumnBigint['max'] = undefined;
72-
let lastWrittenDefault: Models.ColumnBigint['default'] = undefined;
73-
74-
function parseBigintString(str: string): bigint | null {
75-
const trimmed = str.trim();
76-
console.log({ trimmed });
77-
if (!trimmed) return null;
78-
try {
79-
return BigInt(trimmed);
80-
} catch {
81-
return null;
69+
function handleDefaultState(hideDefault: boolean) {
70+
if (hideDefault) {
71+
savedDefault = data.default;
72+
data.default = null;
73+
} else {
74+
data.default = savedDefault;
8275
}
8376
}
8477
78+
const {
79+
stores: { required, array },
80+
listen
81+
} = createConservative<Partial<Models.ColumnBigint>>({
82+
required: false,
83+
array: false,
84+
...data
85+
});
8586
$effect(() => {
86-
// Keep all writes to `data` in a single effect to avoid
87-
// effect-update-depth loops from multiple effects ping-ponging.
88-
const hideDefault = !!data.required || !!data.array;
89-
90-
// Only toggle default visibility on transitions.
91-
if (prevHideDefault === null || prevHideDefault !== hideDefault) {
92-
if (hideDefault) {
93-
// Capture current default once, then clear.
94-
savedDefault = data.default;
95-
data.default = null;
96-
defaultString = '';
97-
lastWrittenDefault = null;
98-
} else {
99-
// Restore (if any) and update the input text.
100-
data.default = savedDefault;
101-
defaultString = savedDefault?.toString() ?? '';
102-
lastWrittenDefault = savedDefault as Models.ColumnBigint['default'];
103-
}
104-
prevHideDefault = hideDefault;
105-
}
106-
107-
const parsedMin = parseBigintString(minString);
108-
minError = minString.trim() && parsedMin === null ? 'Invalid integer' : null;
109-
if (parsedMin !== null || !minString.trim()) {
110-
const next = parsedMin as unknown as Models.ColumnBigint['min'];
111-
if (next !== lastWrittenMin) {
112-
data.min = next;
113-
lastWrittenMin = next;
114-
}
115-
}
116-
117-
const parsedMax = parseBigintString(maxString);
118-
console.log({ parsedMax });
119-
maxError = maxString.trim() && parsedMax === null ? 'Invalid integer' : null;
120-
if (parsedMax !== null || !maxString.trim()) {
121-
const next = parsedMax as unknown as Models.ColumnBigint['max'];
122-
if (next !== lastWrittenMax) {
123-
data.max = next;
124-
lastWrittenMax = next;
125-
}
126-
}
87+
listen(data);
88+
});
12789
128-
// Default is disabled when required or array is enabled.
129-
if (!hideDefault) {
130-
const parsedDefault = parseBigintString(defaultString);
131-
defaultError =
132-
defaultString.trim() && parsedDefault === null ? 'Invalid integer' : null;
133-
if (parsedDefault !== null || !defaultString.trim()) {
134-
const next = parsedDefault as unknown as Models.ColumnBigint['default'];
135-
if (next !== lastWrittenDefault) {
136-
data.default = next;
137-
lastWrittenDefault = next;
138-
}
139-
}
140-
} else {
141-
defaultError = null;
142-
}
90+
$effect(() => {
91+
handleDefaultState($required || $array);
14392
});
14493
</script>
14594

14695
<Layout.Stack direction="row" gap="s">
147-
<InputText
96+
<InputNumber
14897
id="min"
14998
label="Min"
15099
{disabled}
151-
placeholder="Enter integer"
152-
pattern="^-?[0-9]+$"
153-
patternError="Invalid integer"
154-
helper={minError ?? undefined}
155-
bind:value={minString}
100+
placeholder="Enter size"
101+
bind:value={data.min as number}
156102
required={editing} />
157103

158-
<InputText
104+
<InputNumber
159105
id="max"
160106
label="Max"
161107
{disabled}
162-
placeholder="Enter integer"
163-
pattern="^-?[0-9]+$"
164-
patternError="Invalid integer"
165-
helper={maxError ?? undefined}
166-
bind:value={maxString}
108+
placeholder="Enter size"
109+
bind:value={data.max as number}
167110
required={editing} />
168111
</Layout.Stack>
169112

170-
<InputText
113+
<InputNumber
171114
id="default"
172115
label="Default value"
173-
placeholder="Enter integer"
174-
pattern="^-?[0-9]+$"
175-
patternError="Invalid integer"
176-
helper={defaultError ?? undefined}
177-
bind:value={defaultString}
116+
placeholder="Enter value"
117+
min={data.min as number}
118+
max={data.max as number}
119+
bind:value={data.default as number}
178120
disabled={data.required || data.array || disabled}
179121
nullable={(!data.required && !data.array) || disabled} />
180122

src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/columns/column.svelte

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,15 @@
1616
export let label: string;
1717
export let array: boolean | undefined = undefined;
1818
export let optionalText: string | undefined = undefined;
19-
export let value: string | number | boolean | null | string[];
19+
export let value: string | number | bigint | boolean | null | string[] | number[] | bigint[] | boolean[];
2020
export let editing = false;
2121
export let limited = false;
2222
export let column:
2323
| Models.ColumnBoolean
2424
| Models.ColumnEmail
2525
| Models.ColumnEnum
2626
| Models.ColumnFloat
27+
| Models.ColumnBigint
2728
| Models.ColumnInteger
2829
| Models.ColumnIp
2930
| Models.ColumnString
@@ -43,6 +44,7 @@
4344
text: String,
4445
mediumtext: String,
4546
longtext: String,
47+
bigint: Integer,
4648
integer: Integer,
4749
double: Integer,
4850
boolean: Boolean,

src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/columns/types/string.svelte

Lines changed: 6 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,7 @@
1515
}: {
1616
id: string;
1717
label: string;
18-
value:
19-
| string
20-
| number
21-
| bigint
22-
| boolean
23-
| string[]
24-
| number[]
25-
| bigint[]
26-
| boolean[]
27-
| null;
18+
value: string | number | boolean | string[] | number[] | boolean[] | null;
2819
array?: boolean;
2920
limited?: boolean;
3021
column:
@@ -56,26 +47,12 @@
5647
5748
let stringValue = $state('');
5849
59-
function safeStringify(v: unknown): string {
60-
// Note: `JSON.stringify` throws on `bigint` values unless a replacer is used.
61-
return JSON.stringify(v, (_key, value) =>
62-
typeof value === 'bigint' ? value.toString() : value
63-
);
64-
}
65-
66-
function parseValue(str: string | null): number | bigint | boolean | string | null {
50+
function parseValue(str: string | null): number | boolean | string | null {
6751
const trimmed = str?.trim() ?? null;
6852
if (!trimmed) return null;
6953
7054
switch (column.type) {
71-
case 'bigint': {
72-
try {
73-
return BigInt(trimmed);
74-
} catch {
75-
return null;
76-
}
77-
}
78-
55+
case 'bigint':
7956
case 'integer': {
8057
const int = parseInt(trimmed, 10);
8158
return isNaN(int) ? null : int;
@@ -120,8 +97,8 @@
12097
.split(',')
12198
.map((item) => parseValue(item))
12299
.filter((item) => item !== null);
123-
if (safeStringify(newArray) !== safeStringify(value)) {
124-
value = newArray as string[] | number[] | bigint[] | boolean[];
100+
if (JSON.stringify(newArray) !== JSON.stringify(value)) {
101+
value = newArray as string[] | number[] | boolean[];
125102
}
126103
} else {
127104
let parsedValue = parseValue(stringValue);
@@ -138,7 +115,7 @@
138115
}
139116
}
140117
141-
if (safeStringify(parsedValue) !== safeStringify(value)) {
118+
if (JSON.stringify(parsedValue) !== JSON.stringify(value)) {
142119
value = parsedValue;
143120
}
144121
}

src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/store.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export type Columns =
1111
| Models.ColumnEmail
1212
| Models.ColumnEnum
1313
| Models.ColumnFloat
14+
| Models.ColumnBigint
1415
| Models.ColumnInteger
1516
| Models.ColumnIp
1617
| Models.ColumnString

0 commit comments

Comments
 (0)