forj 0.1.9 → 0.1.11
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/package.json +2 -2
- package/src/clause-builder.ts +2 -2
- package/src/d1/model.ts +1 -1
- package/src/dynamodb/client.ts +1 -1
- package/src/dynamodb/compact.ts +8 -8
- package/src/dynamodb/decorators.ts +10 -10
- package/src/dynamodb/model.ts +1 -1
- package/src/dynamodb/repository.ts +1 -1
- package/src/migrations/blueprint.ts +4 -4
- package/src/migrations/builder.ts +2 -2
- package/src/model.ts +4 -2
- package/src/query-builder.ts +10 -10
- package/src/utils.ts +21 -20
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "forj",
|
|
3
3
|
"description": "SQLite ORM and Query Builder whitout dependencies",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.11",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.ts",
|
|
7
7
|
"files": ["src"],
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"@aws-sdk/lib-dynamodb": "^3.1003.0",
|
|
24
24
|
"pathe": "^2.0",
|
|
25
25
|
"pluralize": "^8.0",
|
|
26
|
-
"t0n": "^0.1.
|
|
26
|
+
"t0n": "^0.1.13",
|
|
27
27
|
"zod": "^4.3.6"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
package/src/clause-builder.ts
CHANGED
|
@@ -65,13 +65,13 @@ export default class ClauseBuilder<
|
|
|
65
65
|
logical: ClauseOperator,
|
|
66
66
|
...args: WhereArgs<T>
|
|
67
67
|
) {
|
|
68
|
-
if (typeof args[0]
|
|
68
|
+
if (typeof args[0] === 'function')
|
|
69
69
|
return this.#nested(args[0], logical)
|
|
70
70
|
|
|
71
71
|
const length = args.length
|
|
72
72
|
let [column, operator, value] = args
|
|
73
73
|
|
|
74
|
-
if (length
|
|
74
|
+
if (length === 2) { // @ts-ignore
|
|
75
75
|
value = operator
|
|
76
76
|
operator = '='
|
|
77
77
|
}
|
package/src/d1/model.ts
CHANGED
|
@@ -38,7 +38,7 @@ export abstract class BaseModel<TB extends keyof DB, DB> extends BModel<TB, DB>
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
static DB() {
|
|
41
|
-
if (typeof this.$db
|
|
41
|
+
if (typeof this.$db === 'string') { // TODO: improv compatibility without nodejs_compat
|
|
42
42
|
if (!Envir.has(this.$db))
|
|
43
43
|
throw new Error(`Database '${this.$db}' instance not provided.`)
|
|
44
44
|
|
package/src/dynamodb/client.ts
CHANGED
package/src/dynamodb/compact.ts
CHANGED
|
@@ -70,7 +70,7 @@ export default class Compact {
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
static decode<T = any>(val: string, schema: SchemaStructure): T {
|
|
73
|
-
if (!val || typeof val
|
|
73
|
+
if (!val || typeof val !== 'string') return val as T
|
|
74
74
|
|
|
75
75
|
return this.withSchema(this.unzip(JSON.parse(
|
|
76
76
|
this.#unpack(val)
|
|
@@ -89,7 +89,7 @@ export default class Compact {
|
|
|
89
89
|
if (this.#cantZip(obj)) return obj
|
|
90
90
|
|
|
91
91
|
return schema.map(key => {
|
|
92
|
-
if (typeof key
|
|
92
|
+
if (typeof key === 'string')
|
|
93
93
|
return this.memo(obj[key], seen)
|
|
94
94
|
|
|
95
95
|
const mainKey = Object.keys(key)[0]
|
|
@@ -112,14 +112,14 @@ export default class Compact {
|
|
|
112
112
|
|
|
113
113
|
if (this.#cantZip(val, type, length)) return val
|
|
114
114
|
|
|
115
|
-
if (type
|
|
115
|
+
if (type === 'object') {
|
|
116
116
|
for (const key in val)
|
|
117
117
|
val[key] = this.unzip(val[key], seen)
|
|
118
118
|
|
|
119
119
|
return val
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
-
if (type
|
|
122
|
+
if (type === 'string' && val.startsWith('^')) {
|
|
123
123
|
const item = seen[parseInt(val.slice(1), 10)]
|
|
124
124
|
return item ? item : val
|
|
125
125
|
}
|
|
@@ -143,7 +143,7 @@ export default class Compact {
|
|
|
143
143
|
static entry(key: any, value: any): any {
|
|
144
144
|
if (!key) return undefined
|
|
145
145
|
|
|
146
|
-
if (typeof key
|
|
146
|
+
if (typeof key === 'string')
|
|
147
147
|
return [key, value == null ? null : value]
|
|
148
148
|
|
|
149
149
|
const mainKey = Object.keys(key)[0]
|
|
@@ -166,7 +166,7 @@ export default class Compact {
|
|
|
166
166
|
return val.map(item => this.memo(item, seen))
|
|
167
167
|
|
|
168
168
|
const type = typeof val
|
|
169
|
-
if (type
|
|
169
|
+
if (type === 'object' && val !== null) {
|
|
170
170
|
for (const key in val)
|
|
171
171
|
val[key] = this.memo(val[key], seen)
|
|
172
172
|
|
|
@@ -177,7 +177,7 @@ export default class Compact {
|
|
|
177
177
|
if (this.#cantZip(val, type, length)) return val
|
|
178
178
|
|
|
179
179
|
const index = seen.indexOf(val)
|
|
180
|
-
if (index
|
|
180
|
+
if (index !== -1)
|
|
181
181
|
return `^${index}`
|
|
182
182
|
|
|
183
183
|
seen.push(val)
|
|
@@ -200,6 +200,6 @@ export default class Compact {
|
|
|
200
200
|
static #cantZip(val: any, type: string = '', length: number = 0) {
|
|
201
201
|
if (!val || [null, true, false, 'true', 'false'].includes(val)) return true
|
|
202
202
|
|
|
203
|
-
return !type && !length ? false : type
|
|
203
|
+
return !type && !length ? false : type !== 'object' && length < 2
|
|
204
204
|
}
|
|
205
205
|
}
|
|
@@ -9,7 +9,7 @@ export function getModelMetadata(target: Function | any): ModelMetadata {
|
|
|
9
9
|
return {
|
|
10
10
|
table: target.m[0],
|
|
11
11
|
// @ts-ignore
|
|
12
|
-
keys: typeKeys
|
|
12
|
+
keys: typeKeys !== 'undefined' ? (typeKeys === 'string' ? { PK: target.m[1] } : { PK: target.m[1][0], SK: target.m[1][1] }) : undefined,
|
|
13
13
|
defaultSK: target?.defaultSK || undefined,
|
|
14
14
|
zip: target.m[2] || false,
|
|
15
15
|
fields: target.m[3] || [],
|
|
@@ -18,7 +18,7 @@ export function getModelMetadata(target: Function | any): ModelMetadata {
|
|
|
18
18
|
|
|
19
19
|
function _table(target: Function | any, opt?: ModelOpts) {
|
|
20
20
|
if (!target?.m) target.m = []
|
|
21
|
-
const table = opt ? (typeof opt
|
|
21
|
+
const table = opt ? (typeof opt === 'string' ? opt : opt?.table) : undefined
|
|
22
22
|
|
|
23
23
|
target.m[0] = table || pluralize(target.name.toLocaleUpperCase())
|
|
24
24
|
}
|
|
@@ -36,7 +36,7 @@ function _key(target: Function | any, pk: string, sk?: string) {
|
|
|
36
36
|
|
|
37
37
|
export function _model(target: any, opt?: ModelOpts) {
|
|
38
38
|
_table(target, opt)
|
|
39
|
-
const notStr = typeof opt
|
|
39
|
+
const notStr = typeof opt !== 'string'
|
|
40
40
|
|
|
41
41
|
if (!opt || !notStr || (opt?.zip == null || opt?.zip))
|
|
42
42
|
_zip(target)
|
|
@@ -68,7 +68,7 @@ function _sk(target: any, prop: string) {
|
|
|
68
68
|
export function Entity(target: Function): void
|
|
69
69
|
export function Entity(opt?: ModelOpts): ClassDecorator
|
|
70
70
|
export function Entity(...args: any[]): void | ClassDecorator {
|
|
71
|
-
if (args.length
|
|
71
|
+
if (args.length === 1 && typeof args[0] === 'function')
|
|
72
72
|
return _table(args[0])
|
|
73
73
|
|
|
74
74
|
return (target: any) => _table(target, ...args)
|
|
@@ -77,7 +77,7 @@ export function Entity(...args: any[]): void | ClassDecorator {
|
|
|
77
77
|
export function Model(target: Function): void
|
|
78
78
|
export function Model(opt?: ModelOpts): ClassDecorator
|
|
79
79
|
export function Model(...args: any[]): void | ClassDecorator {
|
|
80
|
-
if (args.length
|
|
80
|
+
if (args.length === 1 && typeof args[0] === 'function')
|
|
81
81
|
return _model(args[0])
|
|
82
82
|
|
|
83
83
|
return (target: any) => _model(target, ...args)
|
|
@@ -86,7 +86,7 @@ export function Model(...args: any[]): void | ClassDecorator {
|
|
|
86
86
|
export function Zip(target: Function): void
|
|
87
87
|
export function Zip(): ClassDecorator
|
|
88
88
|
export function Zip(...args: any[]): void | ClassDecorator {
|
|
89
|
-
if (args.length
|
|
89
|
+
if (args.length === 1 && typeof args[0] === 'function')
|
|
90
90
|
return _zip(args[0])
|
|
91
91
|
|
|
92
92
|
return (target: any) => _zip(target)
|
|
@@ -105,10 +105,10 @@ export function PartitionKey(target: any, propertyKey: string | undefined, param
|
|
|
105
105
|
export function PartitionKey(...args: any[]): void | PropertyDecorator {
|
|
106
106
|
if (!args.length) return
|
|
107
107
|
|
|
108
|
-
if (typeof args[0]
|
|
108
|
+
if (typeof args[0] === 'function' && typeof args[1] === 'string' && args[1])
|
|
109
109
|
return _pk(args[0], args[1])
|
|
110
110
|
|
|
111
|
-
if (args.length
|
|
111
|
+
if (args.length === 1 && args[0])
|
|
112
112
|
return (target: any) => _pk(target, args[0])
|
|
113
113
|
}
|
|
114
114
|
|
|
@@ -118,9 +118,9 @@ export function SortKey(target: any, propertyKey: string | undefined, parameterI
|
|
|
118
118
|
export function SortKey(...args: any[]): void | PropertyDecorator {
|
|
119
119
|
if (!args.length) return
|
|
120
120
|
|
|
121
|
-
if (typeof args[0]
|
|
121
|
+
if (typeof args[0] === 'function' && typeof args[1] === 'string' && args[1])
|
|
122
122
|
return _sk(args[0], args[1])
|
|
123
123
|
|
|
124
|
-
if (args.length
|
|
124
|
+
if (args.length === 1 && args[0])
|
|
125
125
|
return (target: any) => _sk(target, args[0])
|
|
126
126
|
}
|
package/src/dynamodb/model.ts
CHANGED
|
@@ -21,7 +21,7 @@ export default class AbstractModel<T extends object> {
|
|
|
21
21
|
this.#queryBuilder = queryBuilder
|
|
22
22
|
this.#model = model
|
|
23
23
|
|
|
24
|
-
if (typeof (cls as ModelMetadata).table
|
|
24
|
+
if (typeof (cls as ModelMetadata).table === 'string') {
|
|
25
25
|
this.#meta = cls as ModelMetadata
|
|
26
26
|
this.cls = model?.cls
|
|
27
27
|
return
|
|
@@ -95,7 +95,7 @@ export class Blueprint {
|
|
|
95
95
|
enum(name: string, values: string[] | number[]) {
|
|
96
96
|
return this.#column({
|
|
97
97
|
name,
|
|
98
|
-
type: values.every(v => typeof v
|
|
98
|
+
type: values.every(v => typeof v === 'string') ? 'TEXT' : (values.every(v => Number.isInteger(v)) ? 'INTEGER' : 'REAL'),
|
|
99
99
|
// TODO:
|
|
100
100
|
// Checking floating-point numbers can be problematic due to the precision of REAL numbers
|
|
101
101
|
// SQLite might store 0.5 as 0.4999999 or 0.5000001, causing the check to fail
|
|
@@ -103,7 +103,7 @@ export class Blueprint {
|
|
|
103
103
|
// rate NUMERIC(3,1) NOT NULL DEFAULT 0 CHECK(
|
|
104
104
|
// rate IN (0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5)
|
|
105
105
|
// )
|
|
106
|
-
raw: `CHECK(${name} IN (${values.map(v => typeof v
|
|
106
|
+
raw: `CHECK(${name} IN (${values.map(v => typeof v === 'string' ? `'${v.replace(/'/g, "\\'")}'` : v).join(', ')}))`,
|
|
107
107
|
})
|
|
108
108
|
}
|
|
109
109
|
|
|
@@ -112,7 +112,7 @@ export class Blueprint {
|
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
timestamps(columnType: 'int' | 'date' = 'int') {
|
|
115
|
-
const isInt = columnType
|
|
115
|
+
const isInt = columnType === 'int'
|
|
116
116
|
const type = isInt ? 'INTEGER' : 'DATETIME'
|
|
117
117
|
this.#column({ name: 'created_at', type, nullable: true, raw: 'DEFAULT '+ (isInt ? '(unixepoch())' : 'CURRENT_TIMESTAMP') })
|
|
118
118
|
this.#column({ name: 'updated_at', type, nullable: true })
|
|
@@ -120,7 +120,7 @@ export class Blueprint {
|
|
|
120
120
|
}
|
|
121
121
|
|
|
122
122
|
softDelete(columnType: 'int' | 'date' = 'int', name: string = 'deleted_at') {
|
|
123
|
-
this.#column({ name, type: columnType
|
|
123
|
+
this.#column({ name, type: columnType === 'int' ? 'INTEGER' : 'DATETIME', nullable: true })
|
|
124
124
|
return this
|
|
125
125
|
}
|
|
126
126
|
softDeletes(columnType: 'int' | 'date' = 'int', name: string = 'deleted_at') {
|
|
@@ -78,9 +78,9 @@ export default class SchemaBuilder {
|
|
|
78
78
|
sql += 'NULL'
|
|
79
79
|
} else {
|
|
80
80
|
const type = typeof column.default
|
|
81
|
-
if (type
|
|
81
|
+
if (type === 'string') {
|
|
82
82
|
sql += `'${column.default.replace(/'/g, "\\'")}'`
|
|
83
|
-
} else if (type
|
|
83
|
+
} else if (type === 'boolean') {
|
|
84
84
|
sql += Number(column.default)
|
|
85
85
|
} else {
|
|
86
86
|
sql += `${column.default}`.replace(/''/g, "'\\'")
|
package/src/model.ts
CHANGED
|
@@ -38,7 +38,8 @@ export default abstract class Model<TB extends keyof DB, DB> {
|
|
|
38
38
|
M extends typeof Model<TB, DB>,
|
|
39
39
|
I extends InstanceType<M>,
|
|
40
40
|
T extends I['$TShape'],
|
|
41
|
-
|
|
41
|
+
C extends keyof T
|
|
42
|
+
>(this: M, data: Record<C, Value>) {
|
|
42
43
|
return this.builder<I['$DBShape'], T>().insert(data)
|
|
43
44
|
}
|
|
44
45
|
|
|
@@ -46,7 +47,8 @@ export default abstract class Model<TB extends keyof DB, DB> {
|
|
|
46
47
|
M extends typeof Model<TB, DB>,
|
|
47
48
|
I extends InstanceType<M>,
|
|
48
49
|
T extends I['$TShape'],
|
|
49
|
-
|
|
50
|
+
C extends keyof T
|
|
51
|
+
>(this: M, data: Record<C, Value>) {
|
|
50
52
|
return this.builder<I['$DBShape'], T>().update(data)
|
|
51
53
|
}
|
|
52
54
|
|
package/src/query-builder.ts
CHANGED
|
@@ -77,7 +77,7 @@ export default class QueryBuilder<
|
|
|
77
77
|
return await this.#pipe?.run(this)
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
#setType(type: QueryType, data?: Partial<Record<
|
|
80
|
+
#setType<K extends keyof T>(type: QueryType, data?: Partial<Record<K, Value>>) {
|
|
81
81
|
this.#type = type
|
|
82
82
|
if (data) {
|
|
83
83
|
this.#keys = Object.keys(data)
|
|
@@ -87,14 +87,14 @@ export default class QueryBuilder<
|
|
|
87
87
|
return this
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
-
insert(data: Partial<Record<
|
|
90
|
+
insert<K extends keyof T>(data: Partial<Record<K, Value>>) {
|
|
91
91
|
if (this.#opts.timestamps || this.#opts.createdAt) // @ts-ignore
|
|
92
92
|
data.created_at = Timestamp.now()
|
|
93
93
|
|
|
94
94
|
return this.#setType(types.INSERT, data)
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
-
update(data: Partial<Record<
|
|
97
|
+
update<K extends keyof T>(data: Partial<Record<K, Value>>) {
|
|
98
98
|
if (this.#opts.timestamps || this.#opts.updatedAt) // @ts-ignore
|
|
99
99
|
data.updated_at = Timestamp.now()
|
|
100
100
|
|
|
@@ -136,7 +136,7 @@ export default class QueryBuilder<
|
|
|
136
136
|
this.#hasJoin = true
|
|
137
137
|
const query = (type ? type + ' ' : '') + `JOIN ${sqlName(table as string)} ON `
|
|
138
138
|
|
|
139
|
-
if (typeof args[0]
|
|
139
|
+
if (typeof args[0] === 'function') {
|
|
140
140
|
const join = new ClauseBuilder<S[J]>(table as string, this.#schema)
|
|
141
141
|
args[0](join)
|
|
142
142
|
|
|
@@ -148,17 +148,17 @@ export default class QueryBuilder<
|
|
|
148
148
|
const length = args.length
|
|
149
149
|
let [column, operator, value, value2] = args
|
|
150
150
|
|
|
151
|
-
if (length
|
|
151
|
+
if (length === 2) { // @ts-ignore
|
|
152
152
|
value = operator
|
|
153
153
|
operator = '='
|
|
154
|
-
} else if (length
|
|
154
|
+
} else if (length === 3 && !isOperator(operator)) { // @ts-ignore
|
|
155
155
|
value = parseColumn(value as string, operator as string) // TODO: check if value is a valid column
|
|
156
156
|
|
|
157
157
|
if (this.#schema && !isJoinCompare(value, this.#schema))
|
|
158
158
|
throw new Error(`Table column '${value}' doesn't exists.`)
|
|
159
159
|
|
|
160
160
|
operator = '='
|
|
161
|
-
} else if (length
|
|
161
|
+
} else if (length === 4) { // @ts-ignore
|
|
162
162
|
value = parseColumn(value2 as string, value as string)
|
|
163
163
|
operator = '='
|
|
164
164
|
}
|
|
@@ -549,16 +549,16 @@ export default class QueryBuilder<
|
|
|
549
549
|
if (this.#clauses.length)
|
|
550
550
|
sql += ' WHERE '+ this.#clauses.clauses.join(' ')
|
|
551
551
|
|
|
552
|
-
if (this.#type
|
|
552
|
+
if (this.#type === types.SELECT && this.#groups.length)
|
|
553
553
|
sql += ' GROUP BY '+ this.#groups.join(', ')
|
|
554
554
|
|
|
555
555
|
if (this.#orders.length)
|
|
556
556
|
sql += ' ORDER BY '+ this.#orders.join(', ')
|
|
557
557
|
|
|
558
|
-
if (this.#limit
|
|
558
|
+
if (this.#limit !== undefined)
|
|
559
559
|
sql += ' LIMIT '+ this.#limit
|
|
560
560
|
|
|
561
|
-
if (this.#offset
|
|
561
|
+
if (this.#offset !== undefined)
|
|
562
562
|
sql += ' OFFSET '+ this.#offset
|
|
563
563
|
|
|
564
564
|
return sql
|
package/src/utils.ts
CHANGED
|
@@ -12,7 +12,7 @@ export const types = {
|
|
|
12
12
|
const operators = ['=', '!=', '>', '<', '>=', '<=', 'LIKE', 'IN', 'NOT IN', 'IS', 'IS NOT', 'BETWEEN']
|
|
13
13
|
|
|
14
14
|
export function isOperator(o: any) {
|
|
15
|
-
return typeof o
|
|
15
|
+
return typeof o === 'string' && operators.includes(o)
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
export function parseSelectColumn(
|
|
@@ -28,7 +28,7 @@ export function parseSelectColumn(
|
|
|
28
28
|
return col
|
|
29
29
|
|
|
30
30
|
const [table, column] = explicit ? col.split('.') : [baseTable, col]
|
|
31
|
-
if (column
|
|
31
|
+
if (column === '*') return col
|
|
32
32
|
|
|
33
33
|
return `${table}.${column} AS ${pluralize(table, 1)}_${column}`
|
|
34
34
|
}
|
|
@@ -40,14 +40,15 @@ export function parseColumn(name: string, table: string, hasJoin: boolean = true
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
export function formatValue(value: any): string {
|
|
43
|
-
if (value == null || value == undefined)
|
|
43
|
+
// if (value == null || value == undefined)
|
|
44
|
+
if (value == null)
|
|
44
45
|
return 'NULL'
|
|
45
46
|
|
|
46
47
|
const type = typeof value
|
|
47
|
-
if (type
|
|
48
|
+
if (type === 'number' || type === 'bigint')
|
|
48
49
|
return String(value)
|
|
49
50
|
|
|
50
|
-
if (type
|
|
51
|
+
if (type === 'boolean')
|
|
51
52
|
return value ? '1' : '0'
|
|
52
53
|
|
|
53
54
|
if (value instanceof Date)
|
|
@@ -70,7 +71,7 @@ const zodTypeMap: Record<string, string> = {
|
|
|
70
71
|
ZodFunction: 'function',
|
|
71
72
|
}
|
|
72
73
|
|
|
73
|
-
export const isZod = (obj: any): obj is z.ZodTypeAny => obj && typeof obj
|
|
74
|
+
export const isZod = (obj: any): obj is z.ZodTypeAny => obj && typeof obj === 'object' && '_def' in obj
|
|
74
75
|
|
|
75
76
|
const getDef = (schema: any) => schema?._def ?? schema?.def ?? {}
|
|
76
77
|
|
|
@@ -78,7 +79,7 @@ const getTypeName = (def: any): string => {
|
|
|
78
79
|
if (!def) return ''
|
|
79
80
|
if (def.typeName) return def.typeName // zod v3
|
|
80
81
|
if (def.type) { // zod v4
|
|
81
|
-
if (typeof def.type
|
|
82
|
+
if (typeof def.type === 'string') {
|
|
82
83
|
if (def.type.startsWith('Zod')) return def.type
|
|
83
84
|
return 'Zod'+ def.type[0].toUpperCase() + def.type.slice(1)
|
|
84
85
|
// return zodTypeMap[def.type] || def.type
|
|
@@ -99,10 +100,10 @@ const unwrap = (schema: any): any => {
|
|
|
99
100
|
const def = current._def || current?.def
|
|
100
101
|
const type = getTypeName(def)
|
|
101
102
|
|
|
102
|
-
if (type
|
|
103
|
+
if (type === 'ZodNullable')
|
|
103
104
|
allowNull = true
|
|
104
105
|
|
|
105
|
-
if (type
|
|
106
|
+
if (type === 'ZodOptional' || type === 'ZodDefault')
|
|
106
107
|
allowUndefined = true
|
|
107
108
|
|
|
108
109
|
if (['ZodOptional', 'ZodNullable', 'ZodDefault', 'ZodReadonly'].includes(type)) {
|
|
@@ -110,7 +111,7 @@ const unwrap = (schema: any): any => {
|
|
|
110
111
|
continue
|
|
111
112
|
}
|
|
112
113
|
|
|
113
|
-
if (type
|
|
114
|
+
if (type === 'ZodEffects' || type === 'ZodPipeline') {
|
|
114
115
|
current = def.schema || def.innerType || def.out
|
|
115
116
|
continue
|
|
116
117
|
}
|
|
@@ -123,7 +124,7 @@ const unwrap = (schema: any): any => {
|
|
|
123
124
|
}
|
|
124
125
|
|
|
125
126
|
export const zHas = (key: string, schema?: any): boolean => {
|
|
126
|
-
if (!schema || typeof schema
|
|
127
|
+
if (!schema || typeof schema !== 'object' || Array.isArray(schema))
|
|
127
128
|
return false
|
|
128
129
|
|
|
129
130
|
const keys = key.split('.')
|
|
@@ -131,7 +132,7 @@ export const zHas = (key: string, schema?: any): boolean => {
|
|
|
131
132
|
for (const k of keys) {
|
|
132
133
|
schema = unwrap(schema).schema
|
|
133
134
|
|
|
134
|
-
if (!schema || typeof schema
|
|
135
|
+
if (!schema || typeof schema !== 'object')
|
|
135
136
|
return false
|
|
136
137
|
|
|
137
138
|
if (schema.shape && k in schema.shape) {
|
|
@@ -152,7 +153,7 @@ export const zGet = (key: string, schema?: any): [string, z.ZodTypeAny] | false
|
|
|
152
153
|
for (const k of keys) {
|
|
153
154
|
schema = unwrap(schema).schema
|
|
154
155
|
|
|
155
|
-
if (typeof schema
|
|
156
|
+
if (typeof schema !== 'object') return false
|
|
156
157
|
|
|
157
158
|
if (schema?.shape && k in schema.shape) {
|
|
158
159
|
schema = schema.shape[k]
|
|
@@ -201,23 +202,23 @@ export const zSame = (key: string, val: any, schema?: any, deep: boolean = false
|
|
|
201
202
|
|
|
202
203
|
if (!type) return false
|
|
203
204
|
|
|
204
|
-
if (type
|
|
205
|
+
if (type === 'ZodUnion' && def.options)
|
|
205
206
|
return def.options.some((z: any) => zSame(key, val, z, true))
|
|
206
207
|
|
|
207
|
-
if (type
|
|
208
|
+
if (type === 'ZodArray')
|
|
208
209
|
return Array.isArray(val)
|
|
209
210
|
|
|
210
|
-
if (type
|
|
211
|
-
return typeof val
|
|
211
|
+
if (type === 'ZodObject')
|
|
212
|
+
return typeof val === 'object' && val !== null && !Array.isArray(val)
|
|
212
213
|
|
|
213
|
-
if (type
|
|
214
|
+
if (type === 'ZodDate')
|
|
214
215
|
return val instanceof Date
|
|
215
216
|
|
|
216
|
-
return typeof val
|
|
217
|
+
return typeof val === zodTypeMap[type]
|
|
217
218
|
}
|
|
218
219
|
|
|
219
220
|
export function isJoinCompare(val: any, schema?: DBSchema) {
|
|
220
|
-
if (typeof val
|
|
221
|
+
if (typeof val !== 'string' || !val?.includes('.'))
|
|
221
222
|
return false
|
|
222
223
|
|
|
223
224
|
if (!schema)
|