import Schema from "../schema/schema" ; import Client , { CreateIndexOptions } from "../client" ; import Entity from '../entity/entity' ; import Search from '../search/search' ; import { EntityData } from '../entity/entity' ; import HashConverter from "./hash-converter" ; import JsonConverter from "./json-converter" ; /**
 * Initialization data for  Entity creation when calling
 *  Repository . createEntity or  Repository . createAndSave .
  export type EntityCreationData = Record < string , number | boolean | string | string [ ] | null > ; /**
 * A repository is the main interaction point for reading, writing, and
 * removing  Entity from Redis. Create one by passing
 * in a  Schema and a  Client . Then use the  Repository . fetch ,
 *  Repository . save , and  Repository . remove methods to manage your
 * data:
 *
 * ```typescript
 * let repository = new Repository<Foo>(schema, client);
 *
 * let foo = await repository.fetch('01FK6TCJBDK41RJ766A4SBWDJ9');
 * foo.aString = 'bar';
 * foo.aBoolean = false;
 * await repository.save(foo);
 * ```
 *
 * Be sure to use the repository to create a new instance of  Entity you want
 * to create before you save it:
 
 * ```typescript
 * let foo = await repository.createEntity();
 * foo.aString = 'bar';
 * foo.aBoolean = false;
 * await repository.save(foo);
 * ```
 *
 * If you want to the  Repository . search method, you need to create an index
 * first, and you need RediSearch or RedisJSON installed on your instance of Redis:
 *
 * ```typescript
 * await repository.createIndex();
 * let entities = await repository.search()
 *   .where('aString').eq('bar')
 *   .and('aBoolean').is.false().returnAll();
 * ```
 *
 *  template TEntity The type of  Entity that this repository manages.
  export default class Repository < TEntity extends Entity > { private schema : Schema < TEntity > ; private client : Client ; private jsonConverter : JsonConverter ; private hashConverter : HashConverter ; template TEntity The type of  Entity that this repository manages.
     *  param schema The  Schema for this Repository.
     *  param client An open  Client .
      constructor ( schema , client ) { this . schema = schema ; this . client = client ; this . jsonConverter = new JsonConverter ( this . schema . definition ) ; this . hashConverter = new HashConverter ( this . schema . definition ) ; } /**
     * Creates an index in Redis for use by the  Repository . search method. Requires
     * that RediSearch or RedisJSON is installed on your instance of Redis.
      async createIndex ( ) { let options = { indexName : this . schema . indexName , dataStructure : this . schema . dataStructure , prefix : `${ this . schema . prefix }:` , schema : this . schema . redisSchema } ; if ( this . schema . useStopWords === 'OFF' ) options . stopWords = [ ] ; if ( this . schema . useStopWords === 'CUSTOM' ) options . stopWords = this . schema . stopWords ; await this . client . createIndex ( options ) ; } /**
     * Removes an existing index from Redis. Use this method if you want to swap out you index
     * because your  Entity has changed. Requires that RediSearch or RedisJSON is installed
     * on your instance of Redis.
      async dropIndex ( ) { try { await this . client . dropIndex ( this . schema . indexName ) ; } catch ( e ) { if ( e instanceof Error && e . message === "Unknown Index name" ) { } else { throw e ; } } } /**
     * Creates an  Entity with a populated  Entity . entityId property.
     *  param data returns createEntity ( data = { } ) { let id = this . schema . generateId ( ) ; let entity = new this . schema . entityCtor ( this . schema . definition , id ) ; for ( let key in data ) { if ( this . schema . entityCtor . prototype . hasOwnProperty ( key ) ) { ( entity as Record < string , any > ) [ key ] = data [ key ] ; } } return entity ; } /**
     * Save the  Entity to Redis. If it already exists, it will be updated. If it doesn't
     * exist, it will be created.
     *  param entity returns async save ( entity ) { let key = this . makeKey ( entity . entityId ) ; if ( Object . keys ( entity . entityData ) . length === 0 ) { await this . client . unlink ( key ) ; return entity . entityId ; } if ( this . schema . dataStructure === 'JSON' ) { let jsonData = this . jsonConverter . toJsonData ( entity . entityData ) ; await this . client . jsonset ( key , jsonData ) ; } else { let hashData = this . hashConverter . toHashData ( entity . entityData ) ; await this . client . hsetall ( key , hashData ) ; } return entity . entityId ; } /**
     * Creates and saves an  Entity . Equivalent of calling
     *  Repository . createEntity followed by  Repository . save .
     *  param data returns async createAndSave ( data = { } ) { let entity = this . createEntity ( data ) ; await this . save ( entity ) ; return entity ; } /**
     * Read and return an  Entity from Redis with the given id. If
     * the  Entity is not found, returns an  Entity with all
     * properties set to `null`.
     *  param id The ID of the  Entity you seek.
     *  returns async fetch ( id ) { let key = this . makeKey ( id ) ; let entityData = { } ; if ( this . schema . dataStructure === 'JSON' ) { let jsonData = await this . client . jsonget ( key ) ; entityData = this . jsonConverter . toEntityData ( jsonData ) ; } else { let hashData = await this . client . hgetall ( key ) ; entityData = this . hashConverter . toEntityData ( hashData ) ; } let entity = new this . schema . entityCtor ( this . schema . definition , id , entityData ) ; return entity ; } /**
     * Remove an  Entity from Redis with the given id. If the  Entity is
     * not found, does nothing.
     *  param id The ID of the  Entity you with to delete.
      async remove ( id ) { let key = this . makeKey ( id ) ; await this . client . unlink ( key ) ; } template TEntity The type of  Entity sought.
     *  returns A  Search object.
      search ( ) { return new Search < TEntity > ( this . schema , this . client ) ; } private makeKey ( id ) { return `${ this . schema . prefix }:${ id }` ; } }