11import Nano , { DocumentScope } from "nano" ;
22import Validation from './Validation' ; // Import the Validation class
33import BaseEntity from './BaseEntity' ;
4+ import QueryBuilder from './QueryBuilder'
45
56// Type for the entity class constructor
67type EntityClass = {
@@ -11,6 +12,60 @@ type EntityClass = {
1112 [ key : string ] : any ;
1213} ;
1314
15+ // Mango operators
16+ const LOGICAL_OPERATORS = new Set ( [
17+ '$and' , '$or' , '$not' , '$nor' , '$all' , '$elemMatch' , '$allMatch' , '$keyMapMatch'
18+ ] ) ;
19+
20+ const CONDITIONAL_OPERATORS = new Set ( [
21+ '$lt' , '$lte' , '$eq' , '$ne' , '$gte' , '$gt' , '$exists' , '$type' , '$in' , '$nin' ,
22+ '$size' , '$mod' , '$regex' , '$beginsWith'
23+ ] ) ;
24+
25+ function translateSelector (
26+ selector : Record < string , any > ,
27+ fieldMap : Record < string , string >
28+ ) : Record < string , any > {
29+ const translatedSelector : Record < string , any > = { } ;
30+
31+ for ( const [ key , value ] of Object . entries ( selector ) ) {
32+ if ( LOGICAL_OPERATORS . has ( key ) ) {
33+ // Logical operator (e.g., $and): recursively translate each sub-condition
34+ if ( Array . isArray ( value ) ) {
35+ translatedSelector [ key ] = value . map ( ( subSelector ) => translateSelector ( subSelector , fieldMap ) ) ;
36+ } else {
37+ translatedSelector [ key ] = translateSelector ( value , fieldMap ) ;
38+ }
39+ } else if ( CONDITIONAL_OPERATORS . has ( key ) ) {
40+ // Conditional operator (e.g., $eq): Keep the key and value as-is, no further translation needed
41+ translatedSelector [ key ] = value ;
42+ } else {
43+ // Regular field name, so translate it using fieldMap
44+ const translatedField = fieldMap [ key ] || key ;
45+
46+ // If the value is an object and not a conditional operator, translate it recursively
47+ if ( typeof value === 'object' && value !== null && ! Array . isArray ( value ) ) {
48+ const innerKeys = Object . keys ( value ) ;
49+ const isConditional = innerKeys . every ( k => CONDITIONAL_OPERATORS . has ( k ) ) ;
50+
51+ // If all inner keys are conditional, translate the field name and keep conditions as-is
52+ if ( isConditional ) {
53+ translatedSelector [ translatedField ] = value ;
54+ } else {
55+ // Otherwise, translate recursively
56+ translatedSelector [ translatedField ] = translateSelector ( value , fieldMap ) ;
57+ }
58+ } else {
59+ // Primitive or array value, assign directly
60+ translatedSelector [ translatedField ] = value ;
61+ }
62+ }
63+ }
64+
65+ return translatedSelector ;
66+ }
67+
68+
1469const transformToDocumentFormat = function ( data : Record < string , any > , entityClass : EntityClass ) : Record < string , any > {
1570 const transformedData : Record < string , any > = { } ;
1671 const fieldMap = entityClass . fieldMap || { } ;
@@ -99,6 +154,8 @@ const findUsingMango = async function (query: Nano.MangoQuery, entityClass: Enti
99154 }
100155 query . selector [ CouchRepository . getFieldNameFromFieldMap ( entityClass , 'type' ) ] = entityClass . type ;
101156
157+ console . log ( JSON . stringify ( query , null , 4 ) )
158+
102159 // Execute the query
103160 return await connection . find ( query ) ;
104161 } catch ( err ) {
@@ -166,7 +223,7 @@ abstract class CouchRepository {
166223 // 2. Find one document using a Mango selector
167224 async findOne ( selector : any ) : Promise < BaseEntity | null > {
168225 try {
169- const res = await findUsingMango ( { selector } , this . entityClass , this . connection ) ;
226+ const res = await findUsingMango ( { " selector" : translateSelector ( selector , this . entityClass . fieldMap ) } , this . entityClass , this . connection ) ;
170227
171228 if ( res . docs . length === 0 ) {
172229 return null ; // No document found
@@ -181,7 +238,7 @@ abstract class CouchRepository {
181238 // 3. Find one document or fail
182239 async findOneOrFail ( selector : any ) : Promise < BaseEntity > {
183240 try {
184- const res = await findUsingMango ( { selector } , this . entityClass , this . connection ) ;
241+ const res = await findUsingMango ( { " selector" : translateSelector ( selector , this . entityClass . fieldMap ) } , this . entityClass , this . connection ) ;
185242
186243 if ( res . docs . length === 0 ) {
187244 throw new Error ( "Document not found" ) ;
@@ -196,7 +253,7 @@ abstract class CouchRepository {
196253 // 4. Find many documents using a Mango selector
197254 async findMany ( selector : any ) : Promise < BaseEntity [ ] > {
198255 try {
199- const res = await findUsingMango ( { selector } , this . entityClass , this . connection ) ;
256+ const res = await findUsingMango ( { " selector" : translateSelector ( selector , this . entityClass . fieldMap ) } , this . entityClass , this . connection ) ;
200257
201258 return res . docs . map ( ( doc ) => new this . entityClass ( doc ) ) ;
202259 } catch ( err ) {
@@ -298,6 +355,10 @@ abstract class CouchRepository {
298355 return entityAttr ;
299356 }
300357
358+ createQueryBuilder ( ) {
359+ return new QueryBuilder ( ) ;
360+ }
361+
301362}
302363
303364export default CouchRepository ;
0 commit comments