akanjs 2.2.4-rc.3 → 2.2.4-rc.5
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/constant/getDefault.ts
CHANGED
|
@@ -6,7 +6,7 @@ export const getDefault = <T>(fieldObj: FieldObject): DefaultOf<T> => {
|
|
|
6
6
|
const result: Record<string, unknown> = {};
|
|
7
7
|
for (const [key, field] of Object.entries(fieldObj)) {
|
|
8
8
|
if (field.fieldType === "hidden") result[key] = null;
|
|
9
|
-
else if (field.default) {
|
|
9
|
+
else if (field.default !== undefined && field.default !== null) {
|
|
10
10
|
if (typeof field.default === "function") result[key] = (field.default as () => object)();
|
|
11
11
|
else result[key] = field.default as object;
|
|
12
12
|
} else if (field.isArray) result[key] = [];
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@ import { mkdir } from "node:fs/promises";
|
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import type { InArgs, InValue, Client as LibsqlClient } from "@libsql/client";
|
|
6
6
|
import { type BaseEnv, dayjs, FIELD_META, type PromiseOrObject } from "akanjs/base";
|
|
7
|
-
import type
|
|
7
|
+
import { type ConstantModel, getDefault } from "akanjs/constant";
|
|
8
8
|
import {
|
|
9
9
|
createDocumentId,
|
|
10
10
|
type DatabaseModel,
|
|
@@ -300,6 +300,13 @@ const jsonPath = (path: string) =>
|
|
|
300
300
|
.map((part) => part.replaceAll('"', '\\"'))
|
|
301
301
|
.join(".")}`;
|
|
302
302
|
const encodeSqlValue = (value: unknown) => encodeDocumentValue(value);
|
|
303
|
+
|
|
304
|
+
const decodeDateValue = (value: unknown) => {
|
|
305
|
+
if (value === null || value === undefined) return value;
|
|
306
|
+
if (typeof value === "number") return dayjs(value);
|
|
307
|
+
const epoch = Number(value);
|
|
308
|
+
return Number.isNaN(epoch) ? dayjs(value as never) : dayjs(epoch);
|
|
309
|
+
};
|
|
303
310
|
const QUERY_OPERATOR_KEYS = new Set([
|
|
304
311
|
"eq",
|
|
305
312
|
"ne",
|
|
@@ -773,6 +780,9 @@ export class SqliteDocumentStore {
|
|
|
773
780
|
} else {
|
|
774
781
|
doc[key] = value;
|
|
775
782
|
}
|
|
783
|
+
if (doc[key] !== undefined && doc[key] !== null) {
|
|
784
|
+
doc[key] = this.normalizeWriteValue(doc[key], props);
|
|
785
|
+
}
|
|
776
786
|
if (props.enum && doc[key] !== undefined && doc[key] !== null) {
|
|
777
787
|
const values = Array.isArray(doc[key]) ? doc[key] : [doc[key]];
|
|
778
788
|
const fieldEnum = props.enum as { has: (value: unknown) => boolean } | undefined;
|
|
@@ -958,12 +968,28 @@ export class SqliteDocumentStore {
|
|
|
958
968
|
|
|
959
969
|
private decodeDocumentPayload(payload: Record<string, unknown>) {
|
|
960
970
|
const fields = this.database.doc[FIELD_META] as unknown as FieldMap;
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
971
|
+
const result: Record<string, unknown> = {};
|
|
972
|
+
for (const [key, fieldMeta] of Object.entries(fields)) {
|
|
973
|
+
if (BASE_COLUMNS.has(key)) continue;
|
|
974
|
+
const props = fieldMeta.getProps();
|
|
975
|
+
const value = payload[key];
|
|
976
|
+
if (value === undefined) {
|
|
977
|
+
const def = props.default;
|
|
978
|
+
if (def !== undefined && def !== null) {
|
|
979
|
+
result[key] = typeof def === "function" ? (def as (data: unknown) => unknown)(payload) : def;
|
|
980
|
+
} else if (props.nullable) {
|
|
981
|
+
result[key] = null;
|
|
982
|
+
}
|
|
983
|
+
} else {
|
|
984
|
+
result[key] = this.decodeFieldValue(value, props);
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
for (const [key, value] of Object.entries(payload)) {
|
|
988
|
+
if (key in result || BASE_COLUMNS.has(key)) continue;
|
|
989
|
+
const props = fields[key]?.getProps?.();
|
|
990
|
+
result[key] = props ? this.decodeFieldValue(value, props) : value;
|
|
991
|
+
}
|
|
992
|
+
return result;
|
|
967
993
|
}
|
|
968
994
|
|
|
969
995
|
private decodeFieldValue(value: unknown, props: Record<string, unknown>): unknown {
|
|
@@ -973,8 +999,8 @@ export class SqliteDocumentStore {
|
|
|
973
999
|
return new Map(entries.map(([key, item]) => [key, this.decodeMapValue(item, props)]));
|
|
974
1000
|
}
|
|
975
1001
|
if (props.modelRef === Date) {
|
|
976
|
-
if (Array.isArray(value)) return value.map((item) => (item === null ? item :
|
|
977
|
-
return
|
|
1002
|
+
if (Array.isArray(value)) return value.map((item) => (item === null ? item : decodeDateValue(item)));
|
|
1003
|
+
return decodeDateValue(value);
|
|
978
1004
|
}
|
|
979
1005
|
if (Array.isArray(value)) return value.map((item) => this.decodeNestedValue(item, props));
|
|
980
1006
|
return this.decodeNestedValue(value, props);
|
|
@@ -982,7 +1008,7 @@ export class SqliteDocumentStore {
|
|
|
982
1008
|
|
|
983
1009
|
private decodeMapValue(value: unknown, props: Record<string, unknown>) {
|
|
984
1010
|
if (value === undefined || value === null) return value;
|
|
985
|
-
if (props.of === Date) return
|
|
1011
|
+
if (props.of === Date) return decodeDateValue(value);
|
|
986
1012
|
return value;
|
|
987
1013
|
}
|
|
988
1014
|
|
|
@@ -991,12 +1017,44 @@ export class SqliteDocumentStore {
|
|
|
991
1017
|
if (!props.isClass || !props.isScalar) return value;
|
|
992
1018
|
const scalarFields = (props.modelRef as { [FIELD_META]?: FieldMap } | undefined)?.[FIELD_META];
|
|
993
1019
|
if (!scalarFields) return value;
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1020
|
+
const source = value as Record<string, unknown>;
|
|
1021
|
+
const defaults = getDefault(scalarFields as never) as Record<string, unknown>;
|
|
1022
|
+
const result: Record<string, unknown> = {};
|
|
1023
|
+
for (const [key, fieldMeta] of Object.entries(scalarFields)) {
|
|
1024
|
+
const nestedProps = fieldMeta.getProps();
|
|
1025
|
+
const nested = source[key];
|
|
1026
|
+
result[key] = nested === undefined ? defaults[key] : this.decodeFieldValue(nested, nestedProps);
|
|
1027
|
+
}
|
|
1028
|
+
for (const [key, nested] of Object.entries(source)) {
|
|
1029
|
+
if (!(key in result)) result[key] = nested;
|
|
1030
|
+
}
|
|
1031
|
+
return result;
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
private normalizeWriteValue(value: unknown, props: Record<string, unknown>): unknown {
|
|
1035
|
+
if (value === undefined || value === null) return value;
|
|
1036
|
+
if (props.modelRef === Date) {
|
|
1037
|
+
if (Array.isArray(value))
|
|
1038
|
+
return value.map((item) => (item === null || item === undefined ? item : dayjs(item as never)));
|
|
1039
|
+
return dayjs(value as never);
|
|
1040
|
+
}
|
|
1041
|
+
if (!props.isClass || !props.isScalar) return value;
|
|
1042
|
+
if (Array.isArray(value)) return value.map((item) => this.fillScalarDefaults(item, props));
|
|
1043
|
+
return this.fillScalarDefaults(value, props);
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
private fillScalarDefaults(value: unknown, props: Record<string, unknown>): unknown {
|
|
1047
|
+
if (!value || typeof value !== "object") return value;
|
|
1048
|
+
const scalarFields = (props.modelRef as { [FIELD_META]?: FieldMap } | undefined)?.[FIELD_META];
|
|
1049
|
+
if (!scalarFields) return value;
|
|
1050
|
+
const defaults = getDefault(scalarFields as never) as Record<string, unknown>;
|
|
1051
|
+
const result = { ...(value as Record<string, unknown>) };
|
|
1052
|
+
for (const [key, fieldMeta] of Object.entries(scalarFields)) {
|
|
1053
|
+
const nestedProps = fieldMeta.getProps();
|
|
1054
|
+
if (result[key] === undefined) result[key] = defaults[key];
|
|
1055
|
+
else result[key] = this.normalizeWriteValue(result[key], nestedProps);
|
|
1056
|
+
}
|
|
1057
|
+
return result;
|
|
1000
1058
|
}
|
|
1001
1059
|
|
|
1002
1060
|
hydrate(data: DocumentRecord, originalData: DocumentRecord = data) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Database } from "bun:sqlite";
|
|
2
2
|
import type { Client as LibsqlClient } from "@libsql/client";
|
|
3
3
|
import { type BaseEnv, type PromiseOrObject } from "akanjs/base";
|
|
4
|
-
import type
|
|
4
|
+
import { type ConstantModel } from "akanjs/constant";
|
|
5
5
|
import { type DatabaseModel, type DocumentQuery, type DocumentSchema, type DocumentUpdate, type DocumentUpdateOptions, type SchemaOf } from "akanjs/document";
|
|
6
6
|
import type { Sql } from "postgres";
|
|
7
7
|
export interface SqliteDatabaseConfig {
|
|
@@ -256,6 +256,8 @@ export declare class SqliteDocumentStore {
|
|
|
256
256
|
private decodeFieldValue;
|
|
257
257
|
private decodeMapValue;
|
|
258
258
|
private decodeNestedValue;
|
|
259
|
+
private normalizeWriteValue;
|
|
260
|
+
private fillScalarDefaults;
|
|
259
261
|
hydrate(data: DocumentRecord, originalData?: DocumentRecord): any;
|
|
260
262
|
private runHooks;
|
|
261
263
|
private insertStmt;
|
package/ui/Dialog/Modal.tsx
CHANGED
|
@@ -185,7 +185,7 @@ export const Modal = ({ className, bodyClassName, confirmClose, children, onCanc
|
|
|
185
185
|
return createPortal(
|
|
186
186
|
<>
|
|
187
187
|
<div
|
|
188
|
-
className={clsx("fixed inset-0 z-10", showBackground && "animate-fadeIn bg-
|
|
188
|
+
className={clsx("fixed inset-0 z-10", showBackground && "animate-fadeIn bg-black/50 backdrop-blur-md")}
|
|
189
189
|
onClick={(event) => {
|
|
190
190
|
if (event.target !== event.currentTarget) return;
|
|
191
191
|
requestClose();
|