KStorage

« Older   Newer »
 
  Share  
.
  1. raxell
        +2    
     
    .

    User deleted


    Nome della release: KStorage
    Linguaggio di programmazione: Javascript
    Versione: 0.1
    Descrizione: Libreria per la gestione dei dati, con possibilità di persistenza nel LocalStorage.

    E' una libreria che permette di salvare i dati sottoforma di coppie 'chiave' => 'valore'.
    La chiave può essere una stringa semplice (es. user123) oppure una stringa che rappresenta il percorso a una proprietà di un oggetto (es. user123.group.name).
    Possono essere memorizzati valori semplici (numeri, stringhe, booleani) oppure valori strutturati (oggetti, array). La serializzazione dei dati strutturati è automatica (non serve usare JSON.stringify).
    Può essere definito un tempo di vita delle singole chiavi, oltre il quale vengono distrutte.

    La libreria è ancora in una fase iniziale, devo aggiungere e migliorare molte cose e fare dei test decenti per valutarne la correttezza.
    Vorrei comunque qualche parere, sul nome soprattutto (quello che avevo scelto inizialmente era "JStorage" ma pare esista già una libreria con quel nome).

    La documentazione e i dettagli sul funzionamento sono nel codice. Dovrebbe essere abbastanza intuitiva, un esempio di utilizzo è il seguente:
    CODICE
    var db = KStorage('users');
    db.set('u123', {
           name: 'username',
           contacts: {
                   email: 'info@u123.com',
                   twitter: 'https://twitter.com/u123'
           }
    });
    db.get('u123.name'); // => 'username'
    db.set('u123.contacts.email', 'new@u123.com');
    db.remove('u123.contacts.twitter');
    db.exists('u123.contacts.twitter'); // => false
    // invece di usare sempre le chiavi composte è più conveniente salvare
    // un riferimento all'oggetto di interesse
    var contacts = db.get('u123.contacts'); // => { email: 'new@u123.com' }
    contacts.email; // => 'new@u123.com'
    db.save();


    Il codice è sotto spoiler:
    CODICE
    /**
    * Libreria per la gestione dei dati, con possibilità di
    * persistenza degli stessi nel LocalStorage.
    * NB: il LocalStorage può memorizzare un massimo di 5MB, superata
    * questa soglia i dati non possono essere persistiti.
    *
    * Funzionalità:
    *  • i dati sono memorizzati come coppie `chiave`=>`valore`
    *  • la chiave può essere una stringa semplice (es. "user123")
    *    oppure una stringa che rappresenta il percorso a una
    *    proprietà di un oggetto (es. "user123.group.name")
    *  • possono essere memorizzati valori semplici (numeri, stringhe,
    *    booleani) oppure valori strutturati (oggetti, array)
    *  • la serializzazione dei dati strutturati è automatica (non
    *    serve usare `JSON.stringify`)
    *  • può essere definito un tempo di vita delle singole chiavi,
    *    oltre il quale vengono distrutte
    *
    * Esempio di utilizzo:
    *
    *         var db = KStorage('users');
    *         db.set('u123', {
    *                 name: 'username',
    *                 contacts: {
    *                         email: 'info@u123.com',
    *                         twitter: 'https://twitter.com/u123'
    *                 }
    *         });
    *         db.get('u123.name'); // => 'username'
    *         db.set('u123.contacts.email', 'new@u123.com');
    *         db.remove('u123.contacts.twitter');
    *         db.exists('u123.contacts.twitter'); // => false
    *         var contacts = db.get('u123.contacts'); // => { email: 'new@u123.com' }
    *         contacts.email; // => 'new@u123.com'
    *         db.save();
    *
    *
    * @param  {string} localStorageKey         Chiave da usare per persistere i
    *                                          dati nel LocalStorage
    * @param  {string} [metadataKey=           Chiave da usare per salvare le
    *                   _KStorage_metadata]    informazioni addizionali (es.
    *                                          scadenze delle chiavi)
    *
    * @return {Object}
    */
    var KStorage = function(localStorageKey, metadataKey) {
       if (!localStorageKey) {
           throw new Error('[KStorage] invalid key');
       }

       if (!metadataKey) {
           metadataKey = '_KStorage_metadata';
       }

       var data = JSON.parse(localStorage.getItem(localStorageKey)) || Object.create(null);
       var metadata = JSON.parse(localStorage.getItem(metadataKey)) || Object.create(null);

       var checkKey = function(key) {
           if (typeof key !== 'string') {
               throw new Error('[KStorage] invalid key');
           }
       };

       var removeExpiredKeys = function() {
           var currentTime = Date.now();

           for (var key in metadata) {
               if (metadata.hasOwnProperty(key) && metadata[key] < currentTime) {
                   metadata[key] = undefined;
                   removeKey(key);
               }
           }
       };

       var removeKey = function(key) {
           var keyParts = key.split('.');
           var value = data;

           for (var i = 0, length = keyParts.length - 1; i < length; i++) {
               value = value[keyParts[i]];

               if (value === undefined) {
                   return null;
               }
           }

           value[keyParts[length]] = undefined;
       };

       // mantiene la coerenza dei dati tra i tab di uno stesso
       // sito aperti nel browser
       var sync = function() {

       };

       return Object.freeze({
           /**
            * Restituisce il valore corrispondente alla chiave passata come
            * parametro oppure `null` se la chiave non esiste o è scaduta.
            *
            * @param  {?string} key Nome della chiave
            *
            * @return {*}       Valore corrispondente alla chiave
            */
           get: function(key) {
               checkKey(key);

               var keyParts = key.split('.');
               var value = data;

               for (var i = 0, length = keyParts.length - 1; i < length; i++) {
                   value = value[keyParts[i]];

                   if (value === undefined) {
                       return null;
                   }
               }

               var expiration = metadata[key];

               if (expiration && expiration < Date.now()) {
                   value[keyParts[length]] = undefined;
                   metadata[key] = undefined;

                   return null;
               }

               value = value[keyParts[length]];

               if (value === undefined) {
                   return null;
               }

               return value;
           },
           /**
            * Setta il valore per la chiave passata come parametro.
            * Se la chiave esiste già viene sovrascritta.
            *
            * @param  {string} key   Nome della chiave
            * @param  {*}      value Valore da assegnare alla chiave
            */
           set: function(key, value) {
               checkKey(key);

               var keyParts = key.split('.');
               var keyData = data;

               for (var i = 0, length = keyParts.length - 1; i < length; i++) {
                   var keyName = keyParts[i];

                   if (keyData[keyName] === undefined || typeof keyData[keyName] !== 'object') {
                       keyData[keyName] = Object.create(null);
                   }
                   keyData = keyData[keyName];
               }

               keyData[keyParts[length]] = value;
           },
           /**
            * Elimina la chiave passata come parametro.
            *
            * @param  {string} key Nome della chiave
            */
           remove: function(key) {
               checkKey(key);

               removeKey(key);
           },
           /**
            * Verifica l'esistenza della chiave passata come parametro.
            * Una chiave scaduta è considerata inesistente.
            *
            * @param  {string}  key Nome della chiave
            *
            * @return {boolean} `true` se la chiave esiste, `false` altrimenti
            */
           exists: function(key) {
               checkKey(key);

               return this.get(key) !== null;
           },
           /**
            * Imposta un tempo di vita per la chiave passata come parametro.
            * Sovrascrive eventuali scadenza impostate precedentemente.
            *
            * @param  {string} key Nome della chiave
            * @param  {number} ttl Tempo di vita della chiave in millisecondi
            */
           expire: function(key, ttl) {
               checkKey(key);

               if (this.exists(key)) {
                   metadata[key] = Date.now() + ttl;
               }
           },
           /**
            * Restituisce il tipo di dato corrispondente alla chiave passata.
            *
            * @param  {string} key Nome della chiave
            *
            * @return {*}      Tipo di dato corrispondente alla chiave
            */
           type: function(key) {
               checkKey(key);

               return typeof this.get(key);
           },
           /**
            * Restituisce il tempo di vita rimanente della chiave passata
            * come parametro.
            *
            * @param  {string} key Nome della chiave
            * @return {number}     Tempo di vita rimanente in millisecondi
            */
           ttl: function(key) {
               checkKey(key);

               var expiration = metadata[key];
               if (expiration) {
                   return expiration - Date.now();
               }
           },
           /**
            * Persiste i dati nel LocalStorage. Se esiste già una chiave nel
            * LocalStorage con lo stesso nome questa viene sovrascritta.
            * In caso non sia possibile salvare i dati (es. perchè il
            * LocalStorage è disabilitato o perchè la quota massima
            * memorizzabile è stata superata) viene restituito `false`.
            *
            * NB: vista la natura sincrona del LocalStorage è consigliabile
            * persistere i dati solo quando necessario.
            *
            * @return {boolean} `true` in caso di successo, `false` altrimenti
            */
           save: function() {
               removeExpiredKeys();

               try {
                   localStorage.setItem(metadataKey, JSON.stringify(metadata));
                   localStorage.setItem(localStorageKey, JSON.stringify(data));
               }
               catch(e) {
                   return false;
               }

               return true;
           }
       });
    };
     
    .
  2.      
     
    .
    Avatar

    Where there's a user input, there's a vulnerability.

    Group
    Manager
    Posts
    11,133
    Reputazione
    +174

    Status
    Santiddio (in padella), tutte ste righe per una documentazione ahah! Beh, comunque mi pare fatto bene. Non capisco però perché fai
    value[keyParts[length]] = undefined; nel get.
     
    .
  3. raxell
         
     
    .

    User deleted


    CITAZIONE (eXander @ 7/2/2016, 12:15) 
    Santiddio (in padella), tutte ste righe per una documentazione ahah!

    La documentazione è tutto :rotfl: Devo migliorare a scriverla.

    CITAZIONE (eXander @ 7/2/2016, 12:15) 
    Non capisco però perché fai value[keyParts[length]] = undefined; nel get.

    Per eliminare la chiave scaduta.
     
    .
  4. Demøne
         
     
    .

    User deleted


    Questa è una vera release, complimenti!
    Il codice più compatto non lo potevi fare? :asd:
     
    .
3 replies since 7/2/2016, 11:13   104 views
  Share  
.
Top