@mantiq/validation 0.1.3 → 0.2.0

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,6 +1,6 @@
1
1
  {
2
2
  "name": "@mantiq/validation",
3
- "version": "0.1.3",
3
+ "version": "0.2.0",
4
4
  "description": "Rule engine, form requests",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -40,14 +40,15 @@
40
40
  "LICENSE"
41
41
  ],
42
42
  "scripts": {
43
- "build": "bun build ./src/index.ts --outdir ./dist --target bun",
43
+ "build": "bun build ./src/index.ts --outdir ./dist --target bun --packages=external",
44
44
  "test": "bun test",
45
45
  "typecheck": "tsc --noEmit",
46
46
  "clean": "rm -rf dist"
47
47
  },
48
48
  "devDependencies": {
49
49
  "bun-types": "latest",
50
- "typescript": "^5.7.0"
50
+ "typescript": "^5.7.0",
51
+ "@mantiq/core": "workspace:*"
51
52
  },
52
53
  "peerDependencies": {
53
54
  "@mantiq/core": "^0.1.0"
@@ -0,0 +1,45 @@
1
+ import type { PresenceVerifier } from './contracts/PresenceVerifier.ts'
2
+
3
+ /**
4
+ * Database-backed presence verifier for `exists` and `unique` validation rules.
5
+ * Uses the database connection's query builder to check for row existence.
6
+ */
7
+ export class DatabasePresenceVerifier implements PresenceVerifier {
8
+ constructor(private readonly connection: any) {}
9
+
10
+ async getCount(
11
+ table: string,
12
+ column: string,
13
+ value: any,
14
+ excludeId?: string | number | null,
15
+ idColumn = 'id',
16
+ extra: [string, string, any][] = [],
17
+ ): Promise<number> {
18
+ let query = this.connection.table(table).where(column, value)
19
+
20
+ if (excludeId !== undefined && excludeId !== null) {
21
+ query = query.where(idColumn, '!=', excludeId)
22
+ }
23
+
24
+ for (const [col, op, val] of extra) {
25
+ query = query.where(col, op, val)
26
+ }
27
+
28
+ return query.count()
29
+ }
30
+
31
+ async getMultiCount(
32
+ table: string,
33
+ column: string,
34
+ values: any[],
35
+ extra: [string, string, any][] = [],
36
+ ): Promise<number> {
37
+ let query = this.connection.table(table).whereIn(column, values)
38
+
39
+ for (const [col, op, val] of extra) {
40
+ query = query.where(col, op, val)
41
+ }
42
+
43
+ return query.count()
44
+ }
45
+ }
@@ -1,5 +1,7 @@
1
1
  import { ServiceProvider } from '@mantiq/core'
2
2
  import { Validator } from './Validator.ts'
3
+ import { DatabasePresenceVerifier } from './DatabasePresenceVerifier.ts'
4
+ import { setPresenceVerifier } from './helpers/validate.ts'
3
5
  import type { Rule } from './contracts/Rule.ts'
4
6
  import type { PresenceVerifier } from './contracts/PresenceVerifier.ts'
5
7
 
@@ -8,15 +10,11 @@ export const PRESENCE_VERIFIER = Symbol('PresenceVerifier')
8
10
  /**
9
11
  * Registers validation-related bindings in the container.
10
12
  *
11
- * @example
12
- * // In your app bootstrap:
13
- * app.register(new ValidationServiceProvider(app))
14
- *
15
- * // To enable database rules (exists, unique), also bind a PresenceVerifier:
16
- * app.singleton(PRESENCE_VERIFIER, () => new DatabasePresenceVerifier(db))
13
+ * Automatically wires up DatabasePresenceVerifier for `exists` and `unique`
14
+ * rules when @mantiq/database is available.
17
15
  */
18
16
  export class ValidationServiceProvider extends ServiceProvider {
19
- register(): void {
17
+ override register(): void {
20
18
  // Bind a factory that creates pre-configured Validators
21
19
  this.app.bind('validator', () => {
22
20
  return (
@@ -26,15 +24,31 @@ export class ValidationServiceProvider extends ServiceProvider {
26
24
  attributes?: Record<string, string>,
27
25
  ) => {
28
26
  const validator = new Validator(data, rules, messages, attributes)
29
- // Auto-attach presence verifier if one is bound
30
27
  try {
31
28
  const verifier = this.app.make<PresenceVerifier>(PRESENCE_VERIFIER)
32
29
  validator.setPresenceVerifier(verifier)
33
30
  } catch {
34
- // No presence verifier bound — database rules will throw if used
31
+ // No presence verifier bound
35
32
  }
36
33
  return validator
37
34
  }
38
35
  })
39
36
  }
37
+
38
+ override async boot(): Promise<void> {
39
+ // Auto-wire DatabasePresenceVerifier using the default DB connection
40
+ try {
41
+ const { DatabaseManager } = await import('@mantiq/database')
42
+ const dbManager = this.app.make(DatabaseManager)
43
+ const verifier = new DatabasePresenceVerifier(dbManager.connection())
44
+
45
+ // Register in container for validator factory
46
+ this.app.singleton(PRESENCE_VERIFIER, () => verifier)
47
+
48
+ // Set globally for the validate() helper function
49
+ setPresenceVerifier(verifier)
50
+ } catch {
51
+ // @mantiq/database not installed — unique/exists rules unavailable
52
+ }
53
+ }
40
54
  }
@@ -1,4 +1,16 @@
1
1
  import { Validator, type RuleDefinition } from '../Validator.ts'
2
+ import type { PresenceVerifier } from '../contracts/PresenceVerifier.ts'
3
+
4
+ /** Global presence verifier — set by ValidationServiceProvider. */
5
+ let _globalVerifier: PresenceVerifier | null = null
6
+
7
+ export function setPresenceVerifier(verifier: PresenceVerifier): void {
8
+ _globalVerifier = verifier
9
+ }
10
+
11
+ export function getPresenceVerifier(): PresenceVerifier | null {
12
+ return _globalVerifier
13
+ }
2
14
 
3
15
  /**
4
16
  * Validate data against rules. Returns validated data or throws ValidationError.
@@ -6,7 +18,7 @@ import { Validator, type RuleDefinition } from '../Validator.ts'
6
18
  * @example
7
19
  * const data = await validate(
8
20
  * { name: 'Alice', email: 'alice@example.com' },
9
- * { name: 'required|string|max:255', email: 'required|email' },
21
+ * { name: 'required|string|max:255', email: 'required|email|unique:users,email' },
10
22
  * )
11
23
  */
12
24
  export async function validate(
@@ -15,5 +27,9 @@ export async function validate(
15
27
  messages?: Record<string, string>,
16
28
  attributes?: Record<string, string>,
17
29
  ): Promise<Record<string, any>> {
18
- return new Validator(data, rules, messages, attributes).validate()
30
+ const validator = new Validator(data, rules, messages, attributes)
31
+ if (_globalVerifier) {
32
+ validator.setPresenceVerifier(_globalVerifier)
33
+ }
34
+ return validator.validate()
19
35
  }
package/src/index.ts CHANGED
@@ -34,7 +34,10 @@ export {
34
34
  } from './rules/builtin.ts'
35
35
 
36
36
  // ── Helpers ──────────────────────────────────────────────────────────────────
37
- export { validate } from './helpers/validate.ts'
37
+ export { validate, setPresenceVerifier, getPresenceVerifier } from './helpers/validate.ts'
38
+
39
+ // ── Presence Verifier ────────────────────────────────────────────────────────
40
+ export { DatabasePresenceVerifier } from './DatabasePresenceVerifier.ts'
38
41
 
39
42
  // ── Service Provider ─────────────────────────────────────────────────────────
40
43
  export { ValidationServiceProvider, PRESENCE_VERIFIER } from './ValidationServiceProvider.ts'