Skip to content

Commit 272f2e9

Browse files
feat: enhance bigint column support and improve input handling
- Updated bigint column type handling in the database table columns. - Refactored input components to use InputText for bigint values with validation. - Improved parsing and error handling for bigint inputs in string representation. - Adjusted type definitions to include bigint in various contexts.
1 parent 0c38cda commit 272f2e9

3 files changed

Lines changed: 148 additions & 48 deletions

File tree

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,8 +198,15 @@
198198
) {
199199
const stringColumn = column as Models.ColumnString;
200200
return { display: `Size: ${stringColumn.size}` };
201-
} else if (column.type === 'bigint' || column.type === 'integer' || column.type === 'double') {
202-
const numbersColumn = column as Models.ColumnInteger | Models.ColumnFloat;
201+
} else if (
202+
column.type === 'bigint' ||
203+
column.type === 'integer' ||
204+
column.type === 'double'
205+
) {
206+
const numbersColumn = column as
207+
| Models.ColumnBigint
208+
| Models.ColumnInteger
209+
| Models.ColumnFloat;
203210
const { min, max } = numbersColumn;
204211
205212
const isMinBigInt = typeof min === 'bigint';

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

Lines changed: 110 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<script context="module" lang="ts">
1+
<script module lang="ts">
22
import { page } from '$app/state';
33
import { sdk } from '$lib/stores/sdk';
44
import type { Models } from '@appwrite.io/console';
@@ -7,7 +7,7 @@
77
databaseId: string,
88
tableId: string,
99
key: string,
10-
data: Partial<Models.ColumnInteger>
10+
data: Partial<Models.ColumnBigint>
1111
) {
1212
await sdk.forProject(page.params.region, page.params.project).tablesDB.createBigIntColumn({
1313
databaseId,
@@ -24,7 +24,7 @@
2424
export async function updateBigInt(
2525
databaseId: string,
2626
tableId: string,
27-
data: Partial<Models.ColumnInteger>,
27+
data: Partial<Models.ColumnBigint>,
2828
originalKey?: string
2929
) {
3030
await sdk.forProject(page.params.region, page.params.project).tablesDB.updateBigIntColumn({
@@ -42,69 +42,139 @@
4242

4343
<script lang="ts">
4444
import { Layout } from '@appwrite.io/pink-svelte';
45-
import { InputNumber } from '$lib/elements/forms';
46-
import { createConservative } from '$lib/helpers/stores';
45+
import { InputText } from '$lib/elements/forms';
4746
import RequiredArrayCheckboxes from './requiredArrayCheckboxes.svelte';
4847
49-
export let editing = false;
50-
export let disabled = false;
51-
export let data: Partial<Models.ColumnInteger> = {
52-
required: false,
53-
min: 0,
54-
max: 0,
55-
default: 0,
56-
array: false
48+
type Props = {
49+
editing?: boolean;
50+
disabled?: boolean;
51+
data?: Partial<Models.ColumnBigint>;
5752
};
5853
54+
let {
55+
editing = false,
56+
disabled = false,
57+
data = $bindable({ required: false, array: false })
58+
}: Props = $props();
59+
5960
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() ?? '');
6064
61-
function handleDefaultState(hideDefault: boolean) {
62-
if (hideDefault) {
63-
savedDefault = data.default;
64-
data.default = null;
65-
} else {
66-
data.default = savedDefault;
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;
6782
}
6883
}
6984
70-
const {
71-
stores: { required, array },
72-
listen
73-
} = createConservative<Partial<Models.ColumnInteger>>({
74-
required: false,
75-
array: false,
76-
...data
77-
});
78-
$: listen(data);
85+
$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+
}
79106
80-
$: handleDefaultState($required || $array);
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+
}
127+
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+
}
143+
});
81144
</script>
82145

83146
<Layout.Stack direction="row" gap="s">
84-
<InputNumber
147+
<InputText
85148
id="min"
86149
label="Min"
87150
{disabled}
88-
placeholder="Enter size"
89-
bind:value={data.min}
151+
placeholder="Enter integer"
152+
pattern="^-?[0-9]+$"
153+
patternError="Invalid integer"
154+
helper={minError ?? undefined}
155+
bind:value={minString}
90156
required={editing} />
91157

92-
<InputNumber
158+
<InputText
93159
id="max"
94160
label="Max"
95161
{disabled}
96-
placeholder="Enter size"
97-
bind:value={data.max}
162+
placeholder="Enter integer"
163+
pattern="^-?[0-9]+$"
164+
patternError="Invalid integer"
165+
helper={maxError ?? undefined}
166+
bind:value={maxString}
98167
required={editing} />
99168
</Layout.Stack>
100169

101-
<InputNumber
170+
<InputText
102171
id="default"
103172
label="Default value"
104-
placeholder="Enter value"
105-
min={data.min}
106-
max={data.max}
107-
bind:value={data.default}
173+
placeholder="Enter integer"
174+
pattern="^-?[0-9]+$"
175+
patternError="Invalid integer"
176+
helper={defaultError ?? undefined}
177+
bind:value={defaultString}
108178
disabled={data.required || data.array || disabled}
109179
nullable={(!data.required && !data.array) || disabled} />
110180

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

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,16 @@
1515
}: {
1616
id: string;
1717
label: string;
18-
value: string | number | boolean | string[] | number[] | boolean[] | null;
18+
value:
19+
| string
20+
| number
21+
| bigint
22+
| boolean
23+
| string[]
24+
| number[]
25+
| bigint[]
26+
| boolean[]
27+
| null;
1928
array?: boolean;
2029
limited?: boolean;
2130
column:
@@ -47,12 +56,26 @@
4756
4857
let stringValue = $state('');
4958
50-
function parseValue(str: string | null): number | boolean | string | null {
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 {
5167
const trimmed = str?.trim() ?? null;
5268
if (!trimmed) return null;
5369
5470
switch (column.type) {
55-
case 'bigint':
71+
case 'bigint': {
72+
try {
73+
return BigInt(trimmed);
74+
} catch {
75+
return null;
76+
}
77+
}
78+
5679
case 'integer': {
5780
const int = parseInt(trimmed, 10);
5881
return isNaN(int) ? null : int;
@@ -97,8 +120,8 @@
97120
.split(',')
98121
.map((item) => parseValue(item))
99122
.filter((item) => item !== null);
100-
if (JSON.stringify(newArray) !== JSON.stringify(value)) {
101-
value = newArray as string[] | number[] | boolean[];
123+
if (safeStringify(newArray) !== safeStringify(value)) {
124+
value = newArray as string[] | number[] | bigint[] | boolean[];
102125
}
103126
} else {
104127
let parsedValue = parseValue(stringValue);
@@ -115,7 +138,7 @@
115138
}
116139
}
117140
118-
if (JSON.stringify(parsedValue) !== JSON.stringify(value)) {
141+
if (safeStringify(parsedValue) !== safeStringify(value)) {
119142
value = parsedValue;
120143
}
121144
}

0 commit comments

Comments
 (0)