rajt 0.0.15 → 0.0.17

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 CHANGED
@@ -1,18 +1,17 @@
1
1
  {
2
2
  "name": "rajt",
3
3
  "description": "A serverless bundler layer, fully typed for AWS Lambda (Node.js and LLRT) and Cloudflare Workers.",
4
- "version": "0.0.15",
4
+ "version": "0.0.17",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "exports": {
8
8
  ".": "./src/index.ts",
9
9
  "./dynamodb": "./src/dynamodb/index.ts",
10
+ "./dynamodb/types": "./src/dynamodb/types.ts",
10
11
  "./http": "./src/http.ts",
11
12
  "./types": "./src/types.ts"
12
13
  },
13
- "files": [
14
- "src"
15
- ],
14
+ "files": ["src"],
16
15
  "scripts": {
17
16
  "dev": "tsx watch src/dev.ts",
18
17
  "local": "bun run --silent build && bun run --silent sam:local",
@@ -54,6 +53,7 @@
54
53
  "registry": "https://registry.npmjs.org"
55
54
  },
56
55
  "author": "Zunq <open-source@zunq.com>",
56
+ "license": "MIT",
57
57
  "homepage": "https://zunq.dev",
58
58
  "repository": "git://github.com/attla/rajt",
59
59
  "bugs": "https://github.com/attla/rajt/issues",
@@ -3,7 +3,11 @@ import dynamodbLite from '@aws-lite/dynamodb'
3
3
  import AbstractModel from './model'
4
4
 
5
5
  export const aws = await awsLite({
6
- plugins: [dynamodbLite]
6
+ plugins: [dynamodbLite],
7
+ // https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/Package/-aws-sdk-lib-dynamodb/#configuration
8
+ // @ts-ignore
9
+ awsjsonMarshall: {convertClassInstanceToMap: true},
10
+ awsjsonUnmarshall: {convertClassInstanceToMap: true}
7
11
  })
8
12
 
9
13
  export class Dynamodb {
@@ -0,0 +1,149 @@
1
+ import type { SchemaStructure } from './types'
2
+ import getLength from '../utils/lenght'
3
+
4
+ export default class Compact {
5
+ private static typeMap: Record<string, string> = {
6
+ // Null
7
+ 'null,': 'N,',
8
+ ',null': ',N',
9
+ 'null]': 'N]',
10
+ // True
11
+ 'true,': 'T,',
12
+ ',true': ',T',
13
+ 'true]': 'T]',
14
+ // False
15
+ 'false,': 'F,',
16
+ ',false': ',F',
17
+ 'false]': 'F]',
18
+ // Array
19
+ '[],': 'A,',
20
+ ',[]': ',A',
21
+ '[]]': 'A]',
22
+ // Object
23
+ '{},': 'O,',
24
+ ',{}': ',O',
25
+ '{}]': 'O]'
26
+ }
27
+
28
+ static encode(obj: any, schema: SchemaStructure): string {
29
+ const seen: any[] = []
30
+ return this.replaceTypes(
31
+ JSON.stringify(this.zip(obj, schema, seen)).replace(/(,|\[)"(\^\d+)"(\]|,|$)/g, '$1$2$3')
32
+ .replace(/"/g, '~TDQ~')
33
+ .replace(/'/g, '"')
34
+ .replace(/~TDQ~/g, "'")
35
+ .replace(/\\'/g, "^'"),
36
+ this.typeMap
37
+ )
38
+ }
39
+
40
+ static smartDecode<T = any>(val: any, schema: SchemaStructure): T {
41
+ if (!val) return val as T
42
+
43
+ if (Array.isArray(val))
44
+ return val.map((i: { v: string }) => this.decode<T>(i?.V, schema)).filter(Boolean) as T
45
+
46
+ return val?.V ? this.decode<T>(val.V, schema) : val
47
+ }
48
+
49
+ static decode<T = any>(val: string, schema: SchemaStructure): T {
50
+ if (!val) return val as T
51
+
52
+ val = this.replaceTypes(val, this.reverseMap(this.typeMap))
53
+ .replace(/"/g, '~TSQ~')
54
+ .replace(/'/g, '"')
55
+ .replace(/~TSQ~/g, "'")
56
+ .replace(/\^"/g, '\\"')
57
+ .replace(/(,|\[)(\^\d+)(\]|,|$)/g, '$1"$2"$3')
58
+
59
+ return this.withSchema(this.unzip(JSON.parse(val)), schema) as T
60
+ }
61
+
62
+ static zip(obj: any, schema: SchemaStructure, seen: any[]): any[] {
63
+ return schema.map(key => {
64
+ if (typeof key === 'string')
65
+ return this.memo(obj[key], seen)
66
+
67
+ const mainKey = Object.keys(key)[0]
68
+ const subKeys = key[mainKey]
69
+ const val = obj[mainKey]
70
+
71
+ if (Array.isArray(val))
72
+ return val.map(item => this.zip(item, subKeys, seen))
73
+
74
+ return this.zip(val, subKeys, seen)
75
+ })
76
+ }
77
+
78
+ static unzip(array: any[], seen: any[] = [], deep = false): any[] {
79
+ return array.map(item => {
80
+ const length = getLength(item)
81
+
82
+ if ([null, true, false].includes(item) || typeof item !== 'object' && length < 2)
83
+ return item
84
+
85
+ if (Array.isArray(item))
86
+ return this.unzip(item, seen, true)
87
+
88
+ if (typeof item === 'string' && item.startsWith('^')) {
89
+ const pos = parseInt(item.slice(1), 10)
90
+ const val = seen[pos]
91
+ return deep || (val && !`${val}`.startsWith('^')) ? val : item
92
+ }
93
+
94
+ seen.push(item)
95
+ return item
96
+ })
97
+ }
98
+
99
+ static withSchema(value: any[], keys: any[]): any {
100
+ if (!value || !Array.isArray(value))
101
+ return value
102
+
103
+ return Object.fromEntries(
104
+ keys.map((key, index) => this.entry(key, value[index])).filter(Boolean)
105
+ )
106
+ }
107
+
108
+ static entry(key: any, value: any): any {
109
+ if (!key) return undefined
110
+
111
+ if (typeof key === 'string')
112
+ return [key, value]
113
+
114
+ const mainKey = Object.keys(key)[0]
115
+ const subKeys = key[mainKey]
116
+
117
+ if (Array.isArray(value)) {
118
+ if (value.length === 0)
119
+ return [mainKey, []]
120
+
121
+ return Array.isArray(value[0])
122
+ ? [mainKey, value.map(v => this.withSchema(v, subKeys))]
123
+ : [mainKey, this.withSchema(value, subKeys)]
124
+ }
125
+
126
+ return [mainKey, value]
127
+ }
128
+
129
+ static memo(val: any, seen: any[]): any {
130
+ const length = getLength(val)
131
+ // TODO: may be incompatible with empty objects or arrays
132
+ if (typeof val !== 'object' && length < 2) return val
133
+
134
+ const index = seen.indexOf(val)
135
+ if (index !== -1)
136
+ return `^${index}`
137
+
138
+ seen.push(val)
139
+ return val
140
+ }
141
+
142
+ static replaceTypes(str: string, map: Record<string, string>) {
143
+ return Object.entries(map).reduce((s, [from, to]) => s.replaceAll(from, to), str)
144
+ }
145
+
146
+ static reverseMap(map: Record<string, string>): Record<string, string> {
147
+ return Object.fromEntries(Object.entries(map).map(([k, v]) => [v, k]))
148
+ }
149
+ }
@@ -1,17 +1,5 @@
1
1
  import plur from 'plur'
2
-
3
- export type ModelMetadata = {
4
- table: string,
5
- keys?: Record<'PK' | 'SK', string>,
6
- zip: boolean,
7
- }
8
-
9
- export type ModelOpts = string | {
10
- table?: string,
11
- partitionKey?: string,
12
- sortKey?: string,
13
- zip?: boolean,
14
- }
2
+ import type { ModelMetadata, ModelOpts } from './types'
15
3
 
16
4
  export function getModelMetadata(target: Function | any): ModelMetadata {
17
5
  if (!target?.m)
@@ -22,6 +10,7 @@ export function getModelMetadata(target: Function | any): ModelMetadata {
22
10
  table: target.m[0],
23
11
  // @ts-ignore
24
12
  keys: typeKeys !== 'undefined' ? (typeKeys === 'string' ? { PK: target.m[1] } : { PK: target.m[1][0], SK: target.m[1][1] }) : undefined,
13
+ defaultSK: target?.defaultSK || undefined,
25
14
  zip: target.m[2] || false,
26
15
  fields: target.m[3] || [],
27
16
  }
@@ -37,19 +26,19 @@ function _table(target: Function | any, opt?: ModelOpts) {
37
26
  function _zip(target: Function | any) {
38
27
  if (!target?.m) target.m = []
39
28
  target.m[2] = true
40
- target.m[3] = Object.keys(new target)
29
+ target.m[3] = target?.schema || Object.keys(new target)
41
30
  }
42
31
 
43
32
  function _key(target: Function | any, pk: string, sk?: string) {
44
33
  if (!target?.m) target.m = []
45
- target.m[1] = pk && sk? [pk, sk] : [pk]
34
+ target.m[1] = pk && sk ? [pk, sk] : [pk]
46
35
  }
47
36
 
48
37
  function _model(target: any, opt?: ModelOpts) {
49
38
  _table(target, opt)
50
39
  const notStr = typeof opt !== 'string'
51
40
 
52
- if (!opt || notStr && opt?.zip)
41
+ if (!opt || !notStr || (typeof opt?.zip === undefined || opt?.zip))
53
42
  _zip(target)
54
43
 
55
44
  const pk = opt && notStr ? opt?.partitionKey : undefined
@@ -1,14 +1,17 @@
1
1
  import type { AwsLiteDynamoDB } from '@aws-lite/dynamodb-types'
2
+ import type { ModelMetadata, Keys, Model, Filter } from './types'
2
3
  import { getModelMetadata } from './decorators'
3
- import type { ModelMetadata } from './decorators'
4
4
  import QueryBuilder from './query-builder'
5
+ import Compact from './compact'
6
+ import getLength from '../utils/lenght'
5
7
 
6
8
  export default class AbstractModel<T extends object> {
7
9
  private meta: ModelMetadata
10
+ private cls!: Model<T>
8
11
  private lastKey?: Record<string, any>
9
12
 
10
13
  constructor(
11
- cls: (new (...args: any[]) => T) | ModelMetadata,
14
+ cls: Model<T> | ModelMetadata,
12
15
  private db: AwsLiteDynamoDB,
13
16
  private queryBuilder?: QueryBuilder,
14
17
  private model?: AbstractModel<T>
@@ -18,19 +21,19 @@ export default class AbstractModel<T extends object> {
18
21
  return
19
22
  }
20
23
 
21
- // @ts-ignore
22
24
  const meta = getModelMetadata(cls)
23
25
  if (!meta)
24
26
  throw new Error('Missing model metadata')
25
27
 
26
28
  this.meta = meta
29
+ this.cls = cls as Model<T>
27
30
  }
28
31
 
29
32
  get table(): string {
30
33
  return this.meta.table
31
34
  }
32
35
 
33
- get keys() {
36
+ get keySchema() {
34
37
  return this.meta.keys
35
38
  }
36
39
 
@@ -45,48 +48,57 @@ export default class AbstractModel<T extends object> {
45
48
  return this.lastKey
46
49
  }
47
50
 
48
- schema(pk: string, sk?: string) {
49
- if (!this.meta.keys) return {}
50
-
51
- const keys = { [this.meta.keys.PK]: pk }
52
- if (sk && this.meta.keys.SK)
53
- keys[this.meta.keys.SK] = sk
54
-
55
- return keys
56
- }
57
-
58
51
  where(builderFn: (q: QueryBuilder) => void) {
59
52
  const qb = new QueryBuilder()
60
53
  builderFn(qb)
61
- const model = new AbstractModel<T>(this.meta, this.db, qb, this)
62
- return model
54
+ return new AbstractModel<T>(this.meta, this.db, qb, this)
63
55
  }
64
56
 
65
- async scan(filterFn?: (item: T) => boolean) {
57
+ async scan(filterFn?: Filter<T>) {
66
58
  const result = await this.db.Scan({ TableName: this.table, ...this.queryBuilder?.filters })
59
+
67
60
  this.lastEvaluatedKey = result.LastEvaluatedKey
68
- const items = result.Items as T[]
69
- return filterFn ? items.filter(filterFn) : items
61
+ return this.processItems(result.Items, filterFn)
70
62
  }
71
63
 
72
- async query(filterFn?: (item: T) => boolean) {
64
+ async query(filterFn?: Filter<T>) {
73
65
  const result = await this.db.Query({ TableName: this.table, ...this.queryBuilder?.conditions })
66
+
74
67
  this.lastEvaluatedKey = result.LastEvaluatedKey
75
- const items = result.Items as T[]
76
- return filterFn ? items.filter(filterFn) : items
68
+ return this.processItems(result.Items, filterFn)
77
69
  }
78
70
 
79
- async get(pk: string, sk?: string) {
80
- const result = await this.db.GetItem({ TableName: this.table, Key: this.schema(pk, sk) })
81
- return result.Item as T
71
+ async get(key: Keys, sk?: string) {
72
+ const result = await this.db.GetItem({ TableName: this.table, Key: this.key(key, sk) })
73
+ return result.Item ? this.processItem(result.Item) : undefined
82
74
  }
83
75
 
84
- async put(item: Partial<T>) {
76
+ async put(item: Partial<T>, key: Keys) {
77
+ let keys
78
+ if (this.meta.zip) {
79
+ keys = this.getItemKey(item, key)
80
+ this.validateKeys(keys)
81
+ // @ts-ignore
82
+ item = { ...keys, V: Compact.encode(this.getItemWithoutKeys(item), this.meta.fields)}
83
+ } else {
84
+ this.validateKeys(item)
85
+ }
86
+
85
87
  await this.db.PutItem({ TableName: this.table, Item: item })
86
- return item
88
+ return this.processItem(item, keys)
87
89
  }
88
90
 
89
- async update(key: string | [string, string], attrs: Partial<T>) {
91
+ async update(attrs: Partial<T>, key: Keys) {
92
+ let keys
93
+ if (this.meta.zip) {
94
+ keys = this.getItemKey(attrs, key)
95
+ this.validateKeys(keys)
96
+ // @ts-ignore
97
+ attrs = { V: Compact.encode(this.getItemWithoutKeys(attrs), this.meta.fields)}
98
+ } else {
99
+ this.validateKeys(attrs)
100
+ }
101
+
90
102
  const UpdateExpressionParts: string[] = []
91
103
  const ExpressionAttributeValues: any = {}
92
104
  for (const [k, v] of Object.entries(attrs)) {
@@ -96,32 +108,34 @@ export default class AbstractModel<T extends object> {
96
108
  const UpdateExpression = 'SET ' + UpdateExpressionParts.join(', ')
97
109
  const ExpressionAttributeNames = Object.fromEntries(Object.keys(attrs).map(k => [`#${k}`, k]))
98
110
 
99
- return this.db.UpdateItem({
111
+ await this.db.UpdateItem({
100
112
  TableName: this.table,
101
- Key: Array.isArray(key) ? this.schema(key[0], key[1]) : this.schema(key),
113
+ Key: this.key(key),
102
114
  UpdateExpression,
103
115
  ExpressionAttributeValues,
104
116
  ExpressionAttributeNames
105
117
  })
118
+
119
+ return this.processItem(attrs, keys)
106
120
  }
107
121
 
108
- async delete(pk: string, sk?: string) {
109
- return this.db.DeleteItem({ TableName: this.table, Key: this.schema(pk, sk) })
122
+ async delete(key: Keys, sk?: string) {
123
+ return this.db.DeleteItem({ TableName: this.table, Key: this.key(key, sk) })
110
124
  }
111
125
 
112
- async batchGet(keys: Array<{ pk: string, sk?: string }>) {
126
+ async batchGet(keys: Array<Keys>) {
113
127
  const result = await this.db.BatchGetItem({ RequestItems: {
114
- [this.table]: { Keys: keys.map(({ pk, sk }) => this.schema(pk, sk)) }
128
+ [this.table]: { Keys: keys.map(key => this.key(key)) }
115
129
  } })
116
- return result.Responses?.[this.table] as T[]
130
+ return (result.Responses?.[this.table] as T[] || []).map(item => this.processItem(item))
117
131
  }
118
132
 
119
- async batchWrite(items: Array<{ put?: Partial<T>, delete?: { pk: string, sk?: string } }>) {
133
+ async batchWrite(items: Array<{ put?: Partial<T>, delete?: Keys }>) {
120
134
  const WriteRequests = items.map(i => {
121
135
  if (i.put) {
122
136
  return { PutRequest: { Item: i.put } }
123
137
  } else if (i.delete) {
124
- return { DeleteRequest: { Key: this.schema(i.delete.pk, i.delete.sk) } }
138
+ return { DeleteRequest: { Key: this.key(i.delete) } }
125
139
  }
126
140
  return null
127
141
  }).filter(Boolean)
@@ -129,11 +143,121 @@ export default class AbstractModel<T extends object> {
129
143
  return this.db.BatchWriteItem({ RequestItems: {[this.table]: WriteRequests} })
130
144
  }
131
145
 
132
- async deleteMany(keys: Array<{ pk: string, sk?: string }>) {
146
+ async deleteMany(keys: Array<Keys>) {
133
147
  return this.batchWrite(keys.map(k => ({ delete: k })))
134
148
  }
135
149
 
136
150
  async putMany(items: Array<Partial<T>>) {
137
- return this.batchWrite(items.map(i => ({ put: i })))
151
+ return this.batchWrite(items.map(item => ({ put: item })))
152
+ }
153
+
154
+ private key(key: Keys, sk?: string) {
155
+ if (!this.meta.keys) return {}
156
+
157
+ let pk: string
158
+ let skValue: string | undefined
159
+ if (Array.isArray(key)) {
160
+ pk = key[0]
161
+ skValue = key[1] ?? sk
162
+ } else {
163
+ pk = key
164
+ skValue = sk
165
+ }
166
+
167
+ const keys = { [this.meta.keys.PK]: pk }
168
+
169
+ if (this.meta.keys?.SK) {
170
+ if (skValue) {
171
+ keys[this.meta.keys.SK] = skValue
172
+ } else if (this.meta.defaultSK) {
173
+ keys[this.meta.keys.SK] = this.meta.defaultSK
174
+ }
175
+ }
176
+
177
+ return keys
178
+ }
179
+
180
+ private getItemKey(item: Partial<T>, key?: Keys): Record<string, string> {
181
+ if (!this.meta.keys) return {}
182
+
183
+ const keys: Record<string, string> = {}
184
+ if (key)
185
+ this.processExplicitKey(keys, key)
186
+ else if (getLength(item) > 0)
187
+ this.processItemKeys(keys, item)
188
+
189
+ return keys
190
+ }
191
+
192
+ private processExplicitKey(keys: Record<string, string>, key: Keys): void {
193
+ if (!this.meta.keys) return
194
+ if (Array.isArray(key)) {
195
+ keys[this.meta.keys.PK] = key[0]
196
+
197
+ if (this.meta.keys?.SK) {
198
+ if (key.length > 1)
199
+ // @ts-ignore
200
+ keys[this.meta.keys.SK] = key[1]
201
+ else if (this.meta.defaultSK)
202
+ keys[this.meta.keys.SK] = this.meta.defaultSK
203
+ }
204
+ } else {
205
+ keys[this.meta.keys.PK] = String(key)
206
+ }
207
+ }
208
+
209
+ private processItemKeys(keys: Record<string, string>, item: Partial<T>): void {
210
+ if (!this.meta.keys) return
211
+
212
+ const pkValue = item[this.meta.keys.PK as keyof Partial<T>]
213
+ if (pkValue !== undefined)
214
+ keys[this.meta.keys.PK] = String(pkValue)
215
+
216
+ if (this.meta.keys?.SK) {
217
+ const skValue = item[this.meta.keys.SK as keyof Partial<T>]
218
+ if (skValue !== undefined)
219
+ keys[this.meta.keys.SK] = String(skValue)
220
+ else if (this.meta.defaultSK)
221
+ keys[this.meta.keys.SK] = this.meta.defaultSK
222
+ }
223
+ }
224
+
225
+ private validateKeys(keys: Record<string, any>) {
226
+ if (!this.meta.keys)
227
+ throw new Error(`Missing keys of table "${this.table}"`)
228
+
229
+ if (!(this.meta.keys.PK in keys))
230
+ throw new Error(`Missing partition key of table "${this.table}" `)
231
+
232
+ if (this.meta.keys?.SK && !(this.meta.keys.SK in keys))
233
+ throw new Error(`Missing sort key of table "${this.table}"`)
234
+ }
235
+
236
+ private getItemWithoutKeys(item: Partial<T>): Partial<T> {
237
+ if (!this.meta.keys || !item) return { ...item }
238
+
239
+ const { PK, SK } = this.meta.keys
240
+ const { [PK as keyof T]: _, [SK as keyof T]: __, ...rest } = item
241
+
242
+ return rest as Partial<T>
243
+ }
244
+
245
+ private processItems(items: any[] | undefined, filterFn?: Filter<T>): T[] {
246
+ if (!items) return []
247
+
248
+ items = this.meta.zip ? Compact.smartDecode<T[]>(items, this.meta.fields) : items as T[]
249
+ return filterFn ? items.filter(filterFn) : items
250
+ }
251
+
252
+ private processItem(item: any, keys?: Record<string, string>): T {
253
+ if (this.meta.zip && item?.V) {
254
+ const model = new this.cls(Compact.decode(item.V, this.meta.fields))
255
+ if (!keys) keys = this.getItemKey(item)
256
+
257
+ // @ts-ignore
258
+ return model.withKey(keys[this.meta.keys.PK], keys[this.meta.keys.SK] || undefined)
259
+ }
260
+
261
+ return new this.cls(item)
138
262
  }
139
263
  }
@@ -1,11 +1,4 @@
1
- type Operator = '=' | '<>' | '<' | '<=' | '>' | '>=' | 'begins_with' | 'between' | 'in' | 'attribute_exists' | 'attribute_not_exists' | 'attribute_type' | 'contains' | 'size'
2
-
3
- type Condition = {
4
- type: 'filter' | 'keyCondition',
5
- field: string,
6
- operator: Operator,
7
- value: any
8
- }
1
+ import type { Condition, Operator } from './types'
9
2
 
10
3
  export default class QueryBuilder {
11
4
  private _conditions: Condition[] = []
@@ -1,21 +1,19 @@
1
1
  import { z, ZodTypeAny } from 'zod'
2
+ import type { SchemaStructure } from './types'
2
3
 
3
- function extractZodKeys(schema: ZodTypeAny): any {
4
+ function extractZodKeys(schema: ZodTypeAny): SchemaStructure {
4
5
  if (schema instanceof z.ZodObject) {
5
6
  const shape = schema.shape
7
+
6
8
  return Object.entries(shape).map(([key, value]) => {
7
9
  const inner = unwrap(value as ZodTypeAny)
8
10
 
9
- if (inner instanceof z.ZodObject) {
11
+ if (inner instanceof z.ZodObject)
10
12
  return { [key]: extractZodKeys(inner) }
11
- }
12
13
 
13
14
  if (inner instanceof z.ZodArray) {
14
15
  const item = unwrap(inner._def.type as ZodTypeAny)
15
- if (item instanceof z.ZodObject)
16
- return { [key]: extractZodKeys(item) }
17
-
18
- return key
16
+ return item instanceof z.ZodObject ? { [key]: extractZodKeys(item) } : key
19
17
  }
20
18
 
21
19
  return key
@@ -38,13 +36,29 @@ function unwrap(schema: ZodTypeAny): ZodTypeAny {
38
36
  export default function Schema<T extends ZodTypeAny>(schema: T) {
39
37
  return class {
40
38
  static _schema = schema
41
-
42
- static getSchema() {
43
- return extractZodKeys(schema)
44
- }
39
+ static defaultSortKey?: string = undefined
40
+ #PK?: string = undefined
41
+ #SK?: string = undefined
45
42
 
46
43
  constructor(data: z.infer<T>) {
47
44
  Object.assign(this, data)
48
45
  }
46
+
47
+ get PK() { return this.#PK }
48
+ get SK() { return this.#SK }
49
+
50
+ static get schema() {
51
+ return extractZodKeys(this._schema)
52
+ }
53
+
54
+ static get defaultSK() {
55
+ return this.defaultSortKey
56
+ }
57
+
58
+ withKey(key: string, sk?: string) {
59
+ this.#PK = key
60
+ if (sk) this.#SK = sk
61
+ return this
62
+ }
49
63
  }
50
64
  }
@@ -0,0 +1,32 @@
1
+ export type Operator = '=' | '<>' | '<' | '<=' | '>' | '>=' | 'begins_with' | 'between' | 'in' | 'attribute_exists' | 'attribute_not_exists' | 'attribute_type' | 'contains' | 'size'
2
+
3
+ export type Condition = {
4
+ type: 'filter' | 'keyCondition',
5
+ field: string,
6
+ operator: Operator,
7
+ value: any
8
+ }
9
+
10
+ export type ISchemaStructure = string | Record<string, ISchemaStructure[]>
11
+ export type SchemaStructure = ISchemaStructure[]
12
+
13
+ export type KeySchema = Record<'PK' | 'SK', string>
14
+ export type ModelMetadata = {
15
+ table: string,
16
+ keys?: KeySchema,
17
+ defaultSK?: string,
18
+ zip: boolean,
19
+ fields: SchemaStructure,
20
+ }
21
+
22
+ export type ModelOpts = string | {
23
+ table?: string,
24
+ partitionKey?: string,
25
+ sortKey?: string,
26
+ defaultSK?: string,
27
+ zip?: boolean,
28
+ }
29
+
30
+ export type Keys = string | [string] | [string, string]
31
+ export type Model<T extends object> = new (...args: any[]) => T
32
+ export type Filter<T> = (item: T) => boolean
package/src/types.ts CHANGED
@@ -25,13 +25,9 @@ export type LambdaResponse = {
25
25
  export type Errors = Record<string, string | string[]>
26
26
  export type ErrorResponse = {
27
27
  m?: string, // message
28
- // c?: number, // http code
29
28
  e?: Errors, // error bag
30
- // e?: Record<string, string | string[]>, // error bag
31
29
  }
32
30
 
33
- // export type Response<E> = E | ErrorResponse
34
-
35
31
  export type ResponseHeadersInit = [
36
32
  string,
37
33
  string
@@ -0,0 +1,32 @@
1
+ export default function getLength(item: any): number {
2
+ const type = typeof item
3
+
4
+ switch (type) {
5
+ case 'string':
6
+ return item.length
7
+
8
+ case 'number':
9
+ case 'bigint':
10
+ // case 'function':
11
+ return item.toString().length
12
+
13
+ // case 'boolean':
14
+ // return item ? 1 : 0
15
+
16
+ // case 'symbol':
17
+ // return item.toString().length - 8
18
+
19
+ case 'object':
20
+ if (item === null)
21
+ return 0
22
+
23
+ if (Array.isArray(item))
24
+ return item.length
25
+
26
+ return Object.keys(item).length
27
+
28
+ case 'undefined':
29
+ default:
30
+ return 0
31
+ }
32
+ }
@@ -1,5 +1,4 @@
1
1
  import Action, { ActionType } from '../action'
2
- // import BaseMiddleware, { MiddlewareType } from '../middleware'
3
2
 
4
3
  export default function resolve(obj: ActionType) {
5
4
  if (typeof obj === 'function' && obj?.length === 2)
@@ -17,40 +16,3 @@ export default function resolve(obj: ActionType) {
17
16
 
18
17
  throw new Error('Invalid action')
19
18
  }
20
-
21
- // export function resolveMiddleware(obj: MiddlewareType) {
22
- // if (typeof obj === 'function' && obj.length === 2)
23
- // return obj
24
-
25
- // if (obj instanceof BaseMiddleware)
26
- // return obj.handle
27
-
28
- // if (BaseMiddleware.isPrototypeOf(obj)) {
29
- // const instance = new (obj as new () => BaseMiddleware)()
30
- // return instance.handle
31
- // }
32
-
33
- // throw new Error('Invalid middleware provided. Must be a Hono middleware function or MiddlewareClass instance/constructor')
34
- // }
35
-
36
- // // import Action, { ActionType } from '../action'
37
-
38
- // export default function resolve(obj: any) {
39
- // if (typeof obj === 'function' && obj?.length === 2)
40
- // return [obj]
41
-
42
- // // if (obj instanceof Action)
43
- // // return obj.run()
44
-
45
- // // const instance = new (obj as new () => Action)()
46
- // // @ts-ignore
47
- // const instance = new obj()
48
- // // if (Action.isPrototypeOf(obj))
49
- // if (obj?.prototype?.run)
50
- // return instance.run()
51
-
52
- // if (obj?.prototype?.handle)
53
- // return [instance.handle]
54
-
55
- // throw new Error('Invalid action')
56
- // }