New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ability to pass the class name/instance of a custom Table class to db.table #197

Closed
Phuket2 opened this Issue Mar 24, 2018 · 3 comments

Comments

2 participants
@Phuket2

Phuket2 commented Mar 24, 2018

It would be nice to be able to have the ability to pass the class name/instance(one or the other is ok) of a Custom table directly into the Table init method aka db.table('foo', custom_class='my_custom_table_class'). I realise its only one step removed from setting the db.table_class or the global version of it. I think if you want to use several different Custom Table Classes in one database you are relying on order of execution rather than being explicit.
sorry if this is a duplicate, I did search here first

@msiemens

This comment has been minimized.

Owner

msiemens commented Mar 24, 2018

I think if you want to use several different Custom Table Classes in one database you are relying on order of execution rather than being explicit.

That's a good point, although I think the usual use case is to just swap the table class altogether instead of using multiple ones. But I'm open to any pull requests on this 🙂

@Phuket2

This comment has been minimized.

Phuket2 commented Mar 25, 2018

@msiemens , I am still not good enough to do a pull request. I mean in a quality type of way. It's one thing to have the idea, its another thing to bring it altogether. But I did give it a go at least. I accept there could be holes in my general approach.

from tinydb import TinyDB
from tinydb.database import Table
from tinydb.database import StorageProxy

'''
table_override:
    A copy of the table method from database.py
    Make some changes to the method, then patch it below
'''
def table_override(self, name=TinyDB.DEFAULT_TABLE, **options):
        """
        Get access to a specific table.

        Creates a new table, if it hasn't been created before, otherwise it
        returns the cached :class:`~tinydb.Table` object.

        :param name: The name of the table.
        :type name: str
        :param cache_size: How many query results to cache.
        """
        if name in self._table_cache:
            return self._table_cache[name]
        
        # added
        _prev_ctn = self.table_class
        ctn_callable = options.pop('ctn', None)
        
        # added
        if ctn_callable and callable(ctn_callable) :
            self.table_class = ctn_callable
        else:
            _prev_ctn = None

        table = self.table_class(StorageProxy(self._storage, name), name,
                                 **options)
        # added
        if _prev_ctn:
            self.table_class = _prev_ctn
            
        self._table_cache[name] = table

        return table

'''
For testing, replace TinyDB's instance method, db.table().
'''
TinyDB.table = table_override

from faker import Faker
fake = Faker()

def make_dummy_data(num_items=100):
    '''
    Create some dummy data to use
    returns a list of dicts built up using Faker
    '''
    return [
            {'idx': i,
             'first': fake.first_name(),
             'last': fake.last_name(),
             'age': fake.random_int(min=18, max=106),
            }
             for i in range(0, num_items)
           ]


class TableIndexAccess(Table):
    '''
    Crude attempt to add accessing of docs by index by overriding
    __get_item__ in Custom table.
    '''
        
    # don't need the __init__ just put it there to demonstrate. Not using it!
    def __init__(self, storage, name, cache_size=10, *args, **kwargs):
        super().__init__(storage, name, cache_size, *args, **kwargs)
    
    def __getitem__(self, idx):
        '''
        A first attempt to be able to get tdb docs from the db using
        index/slicing notation. Its very ineffient, but if you have small
        datasets and speed is not important seems to work ok. 
        Seems to work!! I am not at a point where I can write tests, so I
        cant be sure its ok. 
        Also would be a little better if tbl.get() supported doc_ids (a list)
        of doc_id's rather that a single doc_id.  
        '''
        ids = list(self._read().keys())[idx]
        ids = ids if isinstance(ids, list) else [ids]
        return [self.get(doc_id=id) for id in ids]


if __name__ == '__main__':
    db_fn = 'table_test.json'            # database filename
    dummy_data = make_dummy_data(500)

    db = TinyDB(db_fn)                    # create TDB instance w/filename
    db.purge_tables()                    # clear all the tables, just for testing
    
    #db.table_class = TableIndexAccess    # Tables created will use TableIndexAccess
    tbl = db.table('test', ctn=TableIndexAccess)   # create a new table
    tbl.insert_multiple(dummy_data)      # add the dummy data to the new table

    # try some slicing
    print(tbl[0:5], '\n')                # first 5 docs
    print(tbl[::len(tbl)-1], '\n')       # first and last docs
    print(tbl[0:50:3], '\n')             # try with step param in slicing
    
    # Try this, the table will be returned from the _table_cache
    # Not a new table!
    tbl = db.table('test')
    print(tbl[0:5], '\n')                # first 5 docs
    print(tbl[::len(tbl)-1], '\n')       # first and last docs
    print(tbl[0:50:3], '\n')             # try with step param in slicing
    
    db.close()                           # close database
    ```

@msiemens msiemens closed this in 6cb6f6a Apr 11, 2018

@msiemens

This comment has been minimized.

Owner

msiemens commented Apr 11, 2018

I've just implemented this as db.table(name, table_class=MyTableClass) 🙂

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment