nuxt-auto-crud 1.4.0 → 1.6.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.
Files changed (36) hide show
  1. package/README.md +113 -84
  2. package/dist/module.d.mts +26 -22
  3. package/dist/module.json +1 -1
  4. package/dist/module.mjs +52 -9
  5. package/dist/runtime/composables/useRelationDisplay.d.ts +12 -0
  6. package/dist/runtime/composables/useRelationDisplay.js +48 -0
  7. package/dist/runtime/composables/useResourceSchemas.d.ts +19 -0
  8. package/dist/runtime/composables/useResourceSchemas.js +17 -0
  9. package/dist/runtime/server/api/[model]/[id].patch.js +3 -0
  10. package/dist/runtime/server/api/[model]/index.get.js +2 -1
  11. package/dist/runtime/server/api/_relations.get.d.ts +2 -0
  12. package/dist/runtime/server/api/_relations.get.js +24 -0
  13. package/dist/runtime/server/api/_schema/[table].get.d.ts +10 -0
  14. package/dist/runtime/server/api/_schema/[table].get.js +32 -0
  15. package/dist/runtime/server/api/_schema/index.get.d.ts +2 -0
  16. package/dist/runtime/server/api/_schema/index.get.js +24 -0
  17. package/dist/runtime/server/plugins/seed.d.ts +2 -0
  18. package/dist/runtime/server/plugins/seed.js +36 -0
  19. package/dist/runtime/server/utils/auth.js +1 -1
  20. package/dist/runtime/server/utils/config.d.ts +2 -2
  21. package/dist/runtime/server/utils/modelMapper.js +16 -8
  22. package/dist/runtime/server/utils/schema.d.ts +20 -0
  23. package/dist/runtime/server/utils/schema.js +70 -0
  24. package/package.json +8 -5
  25. package/src/runtime/composables/useRelationDisplay.ts +67 -0
  26. package/src/runtime/composables/useResourceSchemas.ts +42 -0
  27. package/src/runtime/server/api/[model]/[id].patch.ts +5 -0
  28. package/src/runtime/server/api/[model]/index.get.ts +5 -2
  29. package/src/runtime/server/api/_relations.get.ts +31 -0
  30. package/src/runtime/server/api/_schema/[table].get.ts +41 -0
  31. package/src/runtime/server/api/_schema/index.get.ts +31 -0
  32. package/src/runtime/server/plugins/seed.ts +55 -0
  33. package/src/runtime/server/utils/auth.ts +1 -1
  34. package/src/runtime/server/utils/config.ts +3 -3
  35. package/src/runtime/server/utils/modelMapper.ts +25 -11
  36. package/src/runtime/server/utils/schema.ts +96 -0
@@ -3,7 +3,7 @@
3
3
  import * as schema from '#site/schema'
4
4
  import pluralize from 'pluralize'
5
5
  import { pascalCase } from 'scule'
6
- import { getTableColumns as getDrizzleTableColumns } from 'drizzle-orm'
6
+ import { getTableColumns as getDrizzleTableColumns, getTableName } from 'drizzle-orm'
7
7
  import type { SQLiteTable } from 'drizzle-orm/sqlite-core'
8
8
  import { createError } from 'h3'
9
9
  import { useRuntimeConfig } from '#imports'
@@ -11,7 +11,7 @@ import { useRuntimeConfig } from '#imports'
11
11
  /**
12
12
  * Fields that should never be updatable via PATCH requests
13
13
  */
14
- const PROTECTED_FIELDS = ['id', 'createdAt', 'created_at']
14
+ const PROTECTED_FIELDS = ['id', 'created_at', 'updated_at', 'createdAt', 'updatedAt']
15
15
 
16
16
  /**
17
17
  * Fields that should never be returned in API responses
@@ -50,15 +50,18 @@ function buildModelTableMap(): Record<string, unknown> {
50
50
  // Iterate through all exports from schema
51
51
  for (const [key, value] of Object.entries(schema)) {
52
52
  // Check if it's a Drizzle table
53
- // Drizzle tables have specific properties we can check
54
53
  if (value && typeof value === 'object') {
55
- // Check for common Drizzle table properties
56
- const hasTableSymbol = Symbol.for('drizzle:Name') in value
57
- const hasUnderscore = '_' in value
58
- const hasTableConfig = 'table' in value || '$inferSelect' in value
59
-
60
- if (hasTableSymbol || hasUnderscore || hasTableConfig) {
61
- tableMap[key] = value
54
+ try {
55
+ // getTableName returns the table name for valid tables, and undefined/null for others (like relations)
56
+ // This is a more robust check than checking for properties
57
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
58
+ const tableName = getTableName(value as any)
59
+ if (tableName) {
60
+ tableMap[key] = value
61
+ }
62
+ }
63
+ catch {
64
+ // Ignore if it throws (not a table)
62
65
  }
63
66
  }
64
67
  }
@@ -139,10 +142,21 @@ export function getUpdatableFields(modelName: string): string[] {
139
142
  export function filterUpdatableFields(modelName: string, data: Record<string, unknown>): Record<string, unknown> {
140
143
  const allowedFields = getUpdatableFields(modelName)
141
144
  const filtered: Record<string, unknown> = {}
145
+ const table = modelTableMap[modelName]
146
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
147
+ const columns = table ? getDrizzleTableColumns(table as any) : {}
142
148
 
143
149
  for (const field of allowedFields) {
144
150
  if (data[field] !== undefined) {
145
- filtered[field] = data[field]
151
+ let value = data[field]
152
+ const column = columns[field]
153
+
154
+ // Coerce timestamp fields to Date objects if they are strings
155
+ if (column && column.mode === 'timestamp' && typeof value === 'string') {
156
+ value = new Date(value)
157
+ }
158
+
159
+ filtered[field] = value
146
160
  }
147
161
  }
148
162
 
@@ -0,0 +1,96 @@
1
+ import { getTableColumns } from 'drizzle-orm'
2
+ import { getTableConfig } from 'drizzle-orm/sqlite-core'
3
+ import { modelTableMap } from './modelMapper'
4
+
5
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
6
+ export function drizzleTableToFields(table: any, resourceName: string) {
7
+ const columns = getTableColumns(table)
8
+ const fields = []
9
+
10
+ for (const [key, col] of Object.entries(columns)) {
11
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
12
+ const column = col as any
13
+ const isRequired = column.notNull
14
+ let type = 'string'
15
+ const selectOptions: string[] | undefined = undefined
16
+
17
+ // Map Drizzle types to frontend types
18
+ if (column.dataType === 'number' || column.columnType === 'SQLiteInteger' || column.columnType === 'SQLiteReal') {
19
+ type = 'number'
20
+ // Check if it is a timestamp
21
+ if (column.name.endsWith('_at') || column.name.endsWith('At')) {
22
+ type = 'date'
23
+ }
24
+ }
25
+ else if (column.dataType === 'boolean') {
26
+ type = 'boolean'
27
+ }
28
+ else if (column.dataType === 'date' || (column.dataType === 'string' && (column.name.endsWith('_at') || column.name.endsWith('At')))) {
29
+ type = 'date'
30
+ }
31
+
32
+ fields.push({
33
+ name: key,
34
+ type,
35
+ required: isRequired,
36
+ selectOptions,
37
+ })
38
+ }
39
+
40
+ return {
41
+ resource: resourceName,
42
+ fields,
43
+ }
44
+ }
45
+
46
+ export async function getRelations() {
47
+ const relations: Record<string, Record<string, string>> = {}
48
+
49
+ for (const [tableName, table] of Object.entries(modelTableMap)) {
50
+ try {
51
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
52
+ const config = getTableConfig(table as any)
53
+ if (config.foreignKeys.length > 0) {
54
+ const tableRelations: Record<string, string> = {}
55
+ relations[tableName] = tableRelations
56
+
57
+ // Map column names to property names
58
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
59
+ const columns = getTableColumns(table as any)
60
+ const columnToProperty: Record<string, string> = {}
61
+ for (const [key, col] of Object.entries(columns)) {
62
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
63
+ columnToProperty[(col as any).name] = key
64
+ }
65
+
66
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
67
+ config.foreignKeys.forEach((fk: any) => {
68
+ const sourceColumnName = fk.reference().columns[0].name
69
+ const sourceProperty = columnToProperty[sourceColumnName] || sourceColumnName
70
+ const targetTable = fk.reference().foreignTable[Symbol.for('drizzle:Name')]
71
+ tableRelations[sourceProperty] = targetTable
72
+ })
73
+ }
74
+ }
75
+ catch {
76
+ // Ignore tables that don't have config (e.g. not Drizzle tables)
77
+ }
78
+ }
79
+ return relations
80
+ }
81
+
82
+ export async function getAllSchemas() {
83
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
84
+ const schemas: Record<string, any> = {}
85
+
86
+ for (const [tableName, table] of Object.entries(modelTableMap)) {
87
+ schemas[tableName] = drizzleTableToFields(table, tableName)
88
+ }
89
+ return schemas
90
+ }
91
+
92
+ export async function getSchema(tableName: string) {
93
+ const table = modelTableMap[tableName]
94
+ if (!table) return undefined
95
+ return drizzleTableToFields(table, tableName)
96
+ }