1+ const { sanitize } = require ( "@urbackend/common" ) ;
2+ const mongoose = require ( 'mongoose' ) ;
3+ const { Project } = require ( "@urbackend/common" ) ;
4+ const { getConnection } = require ( "@urbackend/common" ) ;
5+ const { getCompiledModel } = require ( "@urbackend/common" ) ;
6+ const { QueryEngine} = require ( "@urbackend/common" ) ;
7+ const { validateData, validateUpdateData } = require ( "@urbackend/common" ) ;
8+
9+ // Validate MongoDB ObjectId
10+ const isValidId = ( id ) => mongoose . Types . ObjectId . isValid ( id ) ;
11+
12+ // INSERT DATA
13+ module . exports . insertData = async ( req , res ) => {
14+ try {
15+ console . time ( "insert data" )
16+ const { collectionName } = req . params ;
17+ const project = req . project ;
18+
19+ const collectionConfig = project . collections . find ( c => c . name === collectionName ) ;
20+ if ( ! collectionConfig ) return res . status ( 404 ) . json ( { error : "Collection not found" } ) ;
21+
22+ const schemaRules = collectionConfig . model ;
23+ const incomingData = req . body ;
24+
25+ // Recursive validation for all field types
26+ const { error, cleanData } = validateData ( incomingData , schemaRules ) ;
27+ if ( error ) return res . status ( 400 ) . json ( { error } ) ;
28+
29+ const safeData = sanitize ( cleanData ) ;
30+
31+ let docSize = 0 ;
32+ if ( ! project . resources . db . isExternal ) {
33+ docSize = Buffer . byteLength ( JSON . stringify ( safeData ) ) ;
34+ if ( ( project . databaseUsed || 0 ) + docSize > project . databaseLimit ) {
35+ return res . status ( 403 ) . json ( { error : "Database limit exceeded." } ) ;
36+ }
37+ }
38+
39+ const connection = await getConnection ( project . _id ) ;
40+ const Model = getCompiledModel ( connection , collectionConfig , project . _id , project . resources . db . isExternal ) ;
41+
42+ const result = await Model . create ( safeData ) ;
43+
44+ if ( ! project . resources . db . isExternal ) {
45+ await Project . updateOne (
46+ { _id : project . _id } ,
47+ { $inc : { databaseUsed : docSize } }
48+ ) ;
49+ }
50+
51+ console . timeEnd ( "insert data" )
52+ res . status ( 201 ) . json ( result ) ;
53+ } catch ( err ) {
54+ console . error ( err ) ;
55+ res . status ( 500 ) . json ( { error : err . message } ) ;
56+ }
57+ } ;
58+
59+ // GET ALL DATA
60+ module . exports . getAllData = async ( req , res ) => {
61+ try {
62+ console . time ( "getall" )
63+ const { collectionName } = req . params ;
64+ const project = req . project ;
65+
66+ const collectionConfig = project . collections . find ( c => c . name === collectionName ) ;
67+ if ( ! collectionConfig ) return res . status ( 404 ) . json ( { error : "Collection not found" } ) ;
68+
69+ const connection = await getConnection ( project . _id ) ;
70+ const Model = getCompiledModel ( connection , collectionConfig , project . _id , project . resources . db . isExternal ) ;
71+
72+ const features = new QueryEngine ( Model . find ( ) , req . query )
73+ . filter ( )
74+ . sort ( )
75+ . paginate ( ) ;
76+
77+ const data = await features . query . lean ( ) ;
78+ console . timeEnd ( "getall" )
79+ res . json ( data ) ;
80+ } catch ( err ) {
81+ console . error ( err ) ;
82+ res . status ( 500 ) . json ( { error : err . message } ) ;
83+ }
84+ } ;
85+
86+ // GET SINGLE DOC
87+ module . exports . getSingleDoc = async ( req , res ) => {
88+ try {
89+ const { collectionName, id } = req . params ;
90+ const project = req . project ;
91+
92+ // ensure valid mongose objct id
93+ if ( ! isValidId ( id ) ) return res . status ( 400 ) . json ( { error : "Invalid ID format." } ) ;
94+
95+ const collectionConfig = project . collections . find ( c => c . name === collectionName ) ;
96+ if ( ! collectionConfig ) return res . status ( 404 ) . json ( { error : "Collection not found" } ) ;
97+
98+ const connection = await getConnection ( project . _id ) ;
99+ const Model = getCompiledModel ( connection , collectionConfig , project . _id , project . resources . db . isExternal ) ;
100+
101+ const doc = await Model . findById ( id ) . lean ( ) ;
102+ if ( ! doc ) return res . status ( 404 ) . json ( { error : "Document not found." } ) ;
103+
104+ res . json ( doc ) ;
105+ } catch ( err ) {
106+ console . error ( err ) ;
107+ res . status ( 500 ) . json ( { error : err . message } ) ;
108+ }
109+ } ;
110+
111+ // UPDATE DATA
112+ module . exports . updateSingleData = async ( req , res ) => {
113+ try {
114+ const { collectionName, id } = req . params ;
115+ const project = req . project ;
116+ const incomingData = req . body ;
117+
118+ if ( ! isValidId ( id ) ) return res . status ( 400 ) . json ( { error : "Invalid ID format." } ) ;
119+
120+ const collectionConfig = project . collections . find ( c => c . name === collectionName ) ;
121+ if ( ! collectionConfig ) return res . status ( 404 ) . json ( { error : "Collection not found" } ) ;
122+
123+ const connection = await getConnection ( project . _id ) ;
124+ const Model = getCompiledModel ( connection , collectionConfig , project . _id , project . resources . db . isExternal ) ;
125+
126+ // Recursive validation for all field types
127+ const schemaRules = collectionConfig . model ;
128+ const { error : validationError , updateData } = validateUpdateData ( incomingData , schemaRules ) ;
129+ if ( validationError ) return res . status ( 400 ) . json ( { error : validationError } ) ;
130+
131+ const sanitizedData = sanitize ( updateData ) ;
132+
133+ const result = await Model . findByIdAndUpdate ( id , { $set : sanitizedData } , { new : true } ) . lean ( ) ;
134+ if ( ! result ) return res . status ( 404 ) . json ( { error : "Document not found." } ) ;
135+
136+ res . json ( { message : "Updated" , data : result } ) ;
137+ } catch ( err ) {
138+ console . error ( err ) ;
139+ res . status ( 500 ) . json ( { error : err . message } ) ;
140+ }
141+ } ;
142+
143+ // DELETE DATA
144+ module . exports . deleteSingleDoc = async ( req , res ) => {
145+ try {
146+ const { collectionName, id } = req . params ;
147+ const project = req . project ;
148+
149+ if ( ! isValidId ( id ) ) return res . status ( 400 ) . json ( { error : "Invalid ID format." } ) ;
150+
151+ const collectionConfig = project . collections . find ( c => c . name === collectionName ) ;
152+ if ( ! collectionConfig ) return res . status ( 404 ) . json ( { error : "Collection not found" } ) ;
153+
154+ const connection = await getConnection ( project . _id ) ;
155+ const Model = getCompiledModel ( connection , collectionConfig , project . _id , project . resources . db . isExternal ) ;
156+
157+ const docToDelete = await Model . findById ( id ) ;
158+ if ( ! docToDelete ) return res . status ( 404 ) . json ( { error : "Document not found." } ) ;
159+
160+ let docSize = 0 ;
161+ if ( ! project . resources . db . isExternal ) {
162+ docSize = Buffer . byteLength ( JSON . stringify ( docToDelete ) ) ;
163+ }
164+
165+ await Model . deleteOne ( { _id : id } ) ;
166+
167+ if ( ! project . resources . db . isExternal ) {
168+ let databaseUsed = Math . max ( 0 , ( project . databaseUsed || 0 ) - docSize ) ;
169+ await Project . updateOne (
170+ { _id : project . _id } ,
171+ { $set : { databaseUsed } }
172+ ) ;
173+ }
174+
175+ res . json ( { message : "Document deleted" , id } ) ;
176+ } catch ( err ) {
177+ console . error ( err ) ;
178+ res . status ( 500 ) . json ( { error : err . message } ) ;
179+ }
180+ } ;
0 commit comments