diff --git a/README.md b/README.md
index 6d7ff7d..7a7e832 100644
--- a/README.md
+++ b/README.md
@@ -1,85 +1,125 @@
-# Laravel Excel  
+# Laravel Excel
+[![Latest Stable Version](https://poser.pugx.org/cyber-duck/laravel-excel/v/stable)](https://packagist.org/packages/cyber-duck/laravel-excel)
+[![Total Downloads](https://poser.pugx.org/cyber-duck/laravel-excel/downloads)](https://packagist.org/packages/cyber-duck/laravel-excel)
+[![License](https://poser.pugx.org/cyber-duck/laravel-excel/license)](https://raw.githubusercontent.com/Cyber-Duck/laravel-excel/master/LICENSE)
+
+Exporting and importing Excel, CSV and OpenOffice stylesheets using Eloquent Collections and Query Builders in Laravel (5.* and 4.*).  
+It's based on [box/spout](https://github.com/box/spout).
+
+Author: [Simone Todaro](https://github.com/SimoTod)  
+Contributors: [Clément Blanco](https://github.com/Claymm)  
+Made with :heart: by [Cyber-Duck Ltd](http://www.cyber-duck.co.uk)
 
 [Installation](#installation)  
 [Export Excel](#export-excel)  
 [Import Excel](#import-excel)  
 [Different formats](#different-formats)  
 
-This package provides a way to export an Eloquent collection as an excel file and to import a Excel file as an Eloquent collection. It's based on [box/spout](https://github.com/box/spout).
+## Installation
+Use composer to download the package:
+```
+composer require cyber-duck/laravel-excel
+```
+
+### Laravel 4.x
+
+Register the service provider in `config/app.php` by adding this line to providers array.
 
-## Installation  
-The package must be installed directly from [Composer](https://getcomposer.org/).  
-Run the following command:  
+```php
+'providers' => [
+	Cyberduck\LaravelExcel\ExcelLegacyServiceProvider::class,
+],
 ```
-$ composer require cyberduck/laravel-excel
+
+### Laravel < 5.5
+
+Register the service provider in `config/app.php` by adding this line to providers array.
+
+```php
+'providers' => [
+	Cyberduck\LaravelExcel\ExcelServiceProvider::class,
+],
 ```
 
-To make Facades available, register the service provider in config/app.php adding *Cyberduck\LaravelExcel\ExcelServiceProvider* to the provider array.
+### Laravel 5.5
 
-Note. If you are on Laravel 4, use *Cyberduck\LaravelExcel\ExcelLegacyServiceProvider*
+No need to register anything, since it used package auto discovery feature in Laravel 5.5.
 
 ## Export Excel
 
 ### Generate and download an excel file
-Add  
+Add
 ```
 use Exporter;
-```  
+```
 to your controller.
 
-In your action, add
+In your controler function, create a new excel file from an Eloquent collection.
 ```
 $excel = Exporter::make('Excel');
-$excel->load($yourCollection);  
-return $excel->stream($yourFileName);  
-```  
+$excel->load($yourCollection);
+return $excel->stream($yourFileName);
+```
 
-The exporter class is fluent, then you can also write  
+The exporter class is fluent, so you can also write  
 ```
 return Exporter::make('Excel')->load($yourCollection)->stream($yourFileName);
 ```
 
-### Generate and save an excel file
-Add  
+The exporter class supports Query builder objects as well
+```
+$query = DB:table('table')->select('col1','col2');
+$excel = Exporter::make('Excel');
+$excel->loadQuery($query);
+return $excel->stream($yourFileName);
 ```
-use Exporter;
-```  
-to your controller.
 
-In your action, add
+If you deal with big tables, you can set the chunk size to minimise the memory usage
 ```
+$query = DB:table('table')->select('col1','col2');
 $excel = Exporter::make('Excel');
-$excel->load($yourCollection);  
-return $excel->save($yourFileNameWithPath);  
-```  
+$excel->loadQuery($query);
+$excel->setChunk(1000);
+return $excel->stream($yourFileName);
+```
 
-The exporter class is fluent, then you can also write  
+### Generate and save an excel file
+To save the excel file on the server, use the save method.
 ```
-return Exporter::make('Excel')->load($yourCollection)->save($yourFileNameWithPath);
+return $excel->save($yourFileNameWithPath);
 ```
 
 ### Advanced usage
-By default, every element of the Collection become a row and every unprotected field of the Model become a cell. No headers row is printed.
+By default, every element of the Collection becomes a row and every unprotected field of the Model becomes a cell.  
+No headers row is printed.
+
+To change this behaviour, create a class extending *Cyberduck\LaravelExcel\Contract\SerialiserInterface*, implement the methods *getHeaderRow()* and *getData(Model $data)* and set this class on the excel object usint *setSerialiser()*.
+```
+$serialiser = new CustomSerialiser();
+$excel = Exporter::make('Excel');
+$excel->load($collection);
+$excel->setSerialiser($serialiser);
+return $excel->stream($yourFileName);
+```
 
-To change this behaviour, create a class extending *Cyberduck\LaravelExcel\Contract\SerialiserInterface* and implement the methods *getHeaderRow()* and *getData(Model $data)*.  
-*getHeaderRow()* must return an array of string, and every elements is a cell of the first row. To not print the header row, simply return a void array *[]*.  
-*getData(Model $data)* must return an array of string, and every elements is a cell of rows after the header.
+*getHeaderRow()* must return an array of string where every element is a cell of the first row. To not print the header row, simply return a void array *[]*.  
+*getData(Model $data)* must return an array of string, and every elements is a cell.
 
 Example
 ```
-namespace App\Serialiser;
+namespace App\Serialisers;
 
 use Illuminate\Database\Eloquent\Model;
 use Cyberduck\LaravelExcel\Contract\SerialiserInterface;
 
 class ExampleSerialiser implements SerialiserInterface
 {
-    public function getData(Model $data)
+    public function getData($data)
     {
         $row = [];
 
         $row[] = $data->field1;
-        $row[] = $data->relation->field2;
+        $row[] = $data->relationship->field2;
 
         return $row;
     }
@@ -88,14 +128,86 @@ class ExampleSerialiser implements SerialiserInterface
     {
         return [
             'Field 1',
-            'Field 2 (from a relation)'
+            'Field 2 (from a relationship)'
         ];
     }
 }
 ```
+then set the serialiser before saving the file the collection.
+```
+$collection = Exporter::make('Excel')->load($yourCollection)->setSerialiser(new ExampleSerialiser)->stream($yourFileName);
+```
 
 ## Import Excel
-Coming soon! (In development)
+Add
+```
+use Importer;
+```
+to your controller.
+
+In your controler function, import an excel file.
+```
+$excel = Importer::make('Excel');
+$excel->load($filepath);
+$collection = $excel->getCollection();
+//dd($collection)
+```
+
+The importer class is fluent, then you can also write
+```
+return Importer::make('Excel')->load($filepath)->getCollection();
+```
+
+### Advanced usage
+By default, every row of the first sheet of the excel file becomes an array and the final result is wraped in a Collection (Illuminate\Support\Collection).  
+
+To import a different sheet, use *setSheet($sheet)*
+```
+$excel = Importer::make('Excel');
+$excel->load($filepath);
+$excel->setSheet($sheetNumber);
+$collection = $excel->getCollection();
+//dd($collection)
+```
+
+To import each row in an Eloquent model, create a class extending *Cyberduck\LaravelExcel\Contract\ParserInterface* and implement the methods *transform($row)*.  
+
+Example
+```
+namespace App\Parsers;
+
+use App\Models\YourModel;
+use Cyberduck\LaravelExcel\Contract\ParserInterface;
+
+class ExampleParser implements ParserInterface
+{
+    public function transform($row, $header)
+    {
+        $model = new YourModel();
+        $model->field1 = $row[0];
+        $model->field2 = $row[1];
+        // We can manunipulate the data before returning the object
+        $model->field3 = new \Carbon($row[2]);
+        return $model;
+    }
+}
+```
+then set the parser before creating the collection.
+```
+$collection = Importer::make('Excel')->load($filepath)->setParser(new ExampleParser)->getCollection();
+```
 
 ## Different formats
-Coming soon!
+The package supports ODS and CSV files.
+
+### ODS
+```
+$exporter = Exporter::make('OpenOffice');
+$importer = Importer::make('OpenOffice');
+```
+
+### CSV
+```
+$exporter = Exporter::make('Csv');
+$importer = Importer::make('Csv');
+```
diff --git a/composer.json b/composer.json
index a009c4c..c881277 100644
--- a/composer.json
+++ b/composer.json
@@ -1,25 +1,47 @@
 {
-    "name": "cyberduck/laravel-excel",
+    "name": "cyber-duck/laravel-excel",
     "type": "library",
-    "description": "",
-    "keywords": ["Laravel", "Excel"],
-    "require": {
-        "php": ">=5.4.0",
-        "box/spout": "^2.4",
-        "illuminate/database": "4.*|5.1",
-        "illuminate/support": "4.*|5.1"
-    },
+    "description": "This package provides a way to export an Eloquent collection as an excel file and to import a Excel file as an Eloquent collection.",
+    "keywords": ["laravel", "excel", "exporter", "export", "importer", "import", "eloquent", "spout"],
     "license": "MIT",
     "authors": [
         {
             "name": "Simone Todaro",
-            "email": "simone@cyber-duck.co.uk",
+            "email": "simo.todaro@gmail.com",
             "role": "Developer"
         }
     ],
+    "require": {
+        "php": "^7.2.5",
+        "box/spout": "^3.1",
+        "illuminate/database": "^6.0.0|^7.0.0",
+        "illuminate/support": "^6.0.0|^7.0.0"
+    },
+    "require-dev": {
+        "phpunit/phpunit": "^7.0",
+        "phpspec/phpspec": "^6.1.1",
+        "laravel/laravel": "^6.0.0|^7.0.0"
+    },
     "autoload": {
         "psr-4": {
             "Cyberduck\\LaravelExcel\\": "src"
         }
-    }
+    },
+    "autoload-dev": {
+        "files": [
+            "tests/TestCase.php",
+            "tests/utils/Item.php",
+            "tests/utils/Migration.php",
+            "tests/utils/DatabaseSeeder.php",
+            "tests/utils/FirstColumnOnlySerialiser.php"
+        ]
+    },
+    "extra": {
+        "laravel": {
+            "providers": [
+                "Cyberduck\\LaravelExcel\\ExcelServiceProvider"
+            ]
+        }
+    },
+    "minimum-stability": "stable"
 }
diff --git a/phpunit.xml b/phpunit.xml
new file mode 100644
index 0000000..edc9687
--- /dev/null
+++ b/phpunit.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<phpunit backupGlobals="false"
+         backupStaticAttributes="false"
+         bootstrap="vendor/autoload.php"
+         colors="true"
+         convertErrorsToExceptions="true"
+         convertNoticesToExceptions="true"
+         convertWarningsToExceptions="true"
+         processIsolation="false"
+         stopOnFailure="false"
+>
+    <php>
+        <ini name="display_errors" value="On" />
+        <ini name="display_startup_errors" value="On" />
+    </php>
+    <testsuites>
+        <testsuite name="Package Test Suite">
+            <directory suffix=".php">./tests/</directory>
+            <exclude>./tests/views</exclude>
+        </testsuite>
+    </testsuites>
+</phpunit>
\ No newline at end of file
diff --git a/src/Contract/ExporterInterface.php b/src/Contract/ExporterInterface.php
index 75e3a22..61f25bc 100644
--- a/src/Contract/ExporterInterface.php
+++ b/src/Contract/ExporterInterface.php
@@ -1,11 +1,14 @@
 <?php
 namespace Cyberduck\LaravelExcel\Contract;
 
-use Illuminate\Database\Eloquent\Collection;
+use Illuminate\Support\Collection;
+use Illuminate\Database\Query\Builder;
 
 interface ExporterInterface
 {
     public function load(Collection $data);
+    public function loadQuery(Builder $query);
+    public function setChunk($size);
     public function setSerialiser(SerialiserInterface $serialiser);
     public function save($filename);
     public function stream($filename);
diff --git a/src/Contract/ImporterInterface.php b/src/Contract/ImporterInterface.php
index f1f0a0b..1377534 100644
--- a/src/Contract/ImporterInterface.php
+++ b/src/Contract/ImporterInterface.php
@@ -1,11 +1,14 @@
 <?php
 namespace Cyberduck\LaravelExcel\Contract;
 
-use Illuminate\Database\Eloquent\Collection;
+use Illuminate\Database\Eloquent\Model;
 
-interface ExporterInterface
+interface ImporterInterface
 {
     public function load($path);
     public function setParser(ParserInterface $parser);
+    public function setModel(Model $model);
+    public function setSheet($sheet);
     public function getCollection();
+    public function save($updateIfEquals);
 }
diff --git a/src/Contract/ParserInterface.php b/src/Contract/ParserInterface.php
new file mode 100644
index 0000000..71b65e0
--- /dev/null
+++ b/src/Contract/ParserInterface.php
@@ -0,0 +1,7 @@
+<?php
+namespace Cyberduck\LaravelExcel\Contract;
+
+interface ParserInterface
+{
+    public function transform($array, $header);
+}
diff --git a/src/Contract/SerialiserInterface.php b/src/Contract/SerialiserInterface.php
index 311327c..bf85f2f 100644
--- a/src/Contract/SerialiserInterface.php
+++ b/src/Contract/SerialiserInterface.php
@@ -1,10 +1,8 @@
 <?php
 namespace Cyberduck\LaravelExcel\Contract;
 
-use Illuminate\Database\Eloquent\Model;
-
 interface SerialiserInterface
 {
-    public function getData(Model $data);
+    public function getData($data);
     public function getHeaderRow();
 }
diff --git a/src/ExcelServiceProvider.php b/src/ExcelServiceProvider.php
index c5dea63..1aa7f29 100644
--- a/src/ExcelServiceProvider.php
+++ b/src/ExcelServiceProvider.php
@@ -12,8 +12,8 @@ class ExcelServiceProvider extends ServiceProvider
     public function boot()
     {
         $loader = AliasLoader::getInstance();
-        $loader->alias('Exporter', '\Cyberduck\LaravelExcel\ExporterFacade');
-        $loader->alias('Importer', '\Cyberduck\LaravelExcel\ImporterFacade');
+        $loader->alias('Exporter', \Cyberduck\LaravelExcel\ExporterFacade::class);
+        $loader->alias('Importer', \Cyberduck\LaravelExcel\ImporterFacade::class);
     }
 
     public function register()
diff --git a/src/Exporter/AbstractSpreadsheet.php b/src/Exporter/AbstractSpreadsheet.php
index 41cbdec..d3c1118 100644
--- a/src/Exporter/AbstractSpreadsheet.php
+++ b/src/Exporter/AbstractSpreadsheet.php
@@ -1,8 +1,9 @@
 <?php
 namespace Cyberduck\LaravelExcel\Exporter;
 
-use Illuminate\Database\Eloquent\Collection;
-use Box\Spout\Writer\WriterFactory;
+use Illuminate\Support\Collection;
+use Box\Spout\Writer\Common\Creator\WriterEntityFactory;
+use Illuminate\Database\Query\Builder;
 use Cyberduck\LaravelExcel\Serialiser\BasicSerialiser;
 use Cyberduck\LaravelExcel\Contract\SerialiserInterface;
 use Cyberduck\LaravelExcel\Contract\ExporterInterface;
@@ -12,14 +13,22 @@ abstract class AbstractSpreadsheet implements ExporterInterface
     protected $data;
     protected $type;
     protected $serialiser;
+    protected $chuncksize;
+    protected $callbacks;
 
     public function __construct()
     {
         $this->data = [];
         $this->type = $this->getType();
         $this->serialiser = new BasicSerialiser();
+        $this->callbacks = collect([]);
     }
 
+    public function __call($name, $args)
+    {
+        $this->callbacks->push([$name, $args]);
+        return $this;
+    }
 
     public function load(Collection $data)
     {
@@ -27,6 +36,18 @@ public function load(Collection $data)
         return $this;
     }
 
+    public function loadQuery(Builder $query)
+    {
+        $this->data = $query;
+        return $this;
+    }
+
+    public function setChunk($size)
+    {
+        $this->chunksize = $size;
+        return $this;
+    }
+
     public function setSerialiser(SerialiserInterface $serialiser)
     {
         $this->serialiser = $serialiser;
@@ -35,6 +56,8 @@ public function setSerialiser(SerialiserInterface $serialiser)
 
     abstract public function getType();
 
+    abstract public function createWriter();
+
     public function save($filename)
     {
         $writer = $this->create();
@@ -53,18 +76,38 @@ public function stream($filename)
 
     protected function create()
     {
-        return WriterFactory::create($this->type);
+        $writer = $this->createWriter();
+        $this->callbacks->each(function ($elem) use (&$writer) {
+            call_user_func_array(array($writer, $elem[0]), $elem[1]);
+        });
+        return $writer;
     }
 
     protected function makeRows($writer)
     {
         $headerRow = $this->serialiser->getHeaderRow();
         if (!empty($headerRow)) {
-            $writer->addRow($headerRow);
+            $row = WriterEntityFactory::createRowFromArray($headerRow);
+            $writer->addRow($row);
         }
-        foreach ($this->data as $record) {
-            $writer->addRow($this->serialiser->getData($record));
+        if ($this->data instanceof Builder) {
+            if (isset($this->chuncksize)) {
+                $this->data->chunk($this->chuncksize);
+            } else {
+                $this->addRowsDataToWriter($this->data->get(), $writer);
+            }
+        } else {
+            $this->addRowsDataToWriter($this->data, $writer);
         }
         return $writer;
     }
+
+    public function addRowsDataToWriter($data, $writer)
+    {
+        foreach ($data as $record) {
+            $recordData = $this->serialiser->getData($record);
+            $row = WriterEntityFactory::createRowFromArray($recordData);
+            $writer->addRow($row);
+        }
+    }
 }
diff --git a/src/Exporter/Csv.php b/src/Exporter/Csv.php
index 6fda1a6..8fe2c18 100644
--- a/src/Exporter/Csv.php
+++ b/src/Exporter/Csv.php
@@ -2,6 +2,7 @@
 namespace Cyberduck\LaravelExcel\Exporter;
 
 use Box\Spout\Common\Type;
+use Box\Spout\Writer\Common\Creator\WriterEntityFactory;
 
 class Csv extends AbstractSpreadsheet
 {
@@ -9,4 +10,9 @@ public function getType()
     {
         return Type::CSV;
     }
+
+    public function createWriter()
+    {
+        return WriterEntityFactory::createCSVWriter();
+    }
 }
diff --git a/src/Exporter/Excel.php b/src/Exporter/Excel.php
index 0a858a0..8983e6e 100644
--- a/src/Exporter/Excel.php
+++ b/src/Exporter/Excel.php
@@ -2,6 +2,7 @@
 namespace Cyberduck\LaravelExcel\Exporter;
 
 use Box\Spout\Common\Type;
+use Box\Spout\Writer\Common\Creator\WriterEntityFactory;
 
 class Excel extends AbstractSpreadsheet
 {
@@ -9,4 +10,9 @@ public function getType()
     {
         return Type::XLSX;
     }
+
+    public function createWriter()
+    {
+        return WriterEntityFactory::createXLSXWriter();
+    }
 }
diff --git a/src/Exporter/OpenOffice.php b/src/Exporter/OpenOffice.php
index 9e28199..15b0970 100644
--- a/src/Exporter/OpenOffice.php
+++ b/src/Exporter/OpenOffice.php
@@ -2,6 +2,7 @@
 namespace Cyberduck\LaravelExcel\Exporter;
 
 use Box\Spout\Common\Type;
+use Box\Spout\Writer\Common\Creator\WriterEntityFactory;
 
 class OpenOffice extends AbstractSpreadsheet
 {
@@ -9,4 +10,9 @@ public function getType()
     {
         return Type::ODS;
     }
+
+    public function createWriter()
+    {
+        return WriterEntityFactory::createODSWriter();
+    }
 }
diff --git a/src/Importer/AbstractSpreadsheet.php b/src/Importer/AbstractSpreadsheet.php
index 12fa276..d94d337 100644
--- a/src/Importer/AbstractSpreadsheet.php
+++ b/src/Importer/AbstractSpreadsheet.php
@@ -1,8 +1,7 @@
 <?php
 namespace Cyberduck\LaravelExcel\Importer;
 
-use Illuminate\Database\Eloquent\Collection;
-use Box\Spout\Reader\ReaderFactory;
+use Illuminate\Database\Eloquent\Model;
 use Cyberduck\LaravelExcel\Parser\BasicParser;
 use Cyberduck\LaravelExcel\Contract\ParserInterface;
 use Cyberduck\LaravelExcel\Contract\ImporterInterface;
@@ -13,57 +12,160 @@ abstract class AbstractSpreadsheet implements ImporterInterface
     protected $type;
     protected $parser;
     protected $sheet;
+    protected $model;
+    protected $hasHeaderRow;
+    protected $callbacks;
 
     public function __construct()
     {
         $this->path = '';
-        $this->sheet = 0;
+        $this->sheet = 1;
+        $this->hasHeaderRow = 0;
         $this->type = $this->getType();
         $this->parser = new BasicParser();
+        $this->model = false;
+        $this->callbacks = collect([]);
+    }
+
+    public function __call($name, $args)
+    {
+        $this->callbacks->push([$name, $args]);
+        return $this;
     }
 
     public function load($path)
     {
         $this->path = $path;
+        return $this;
     }
 
     public function setSheet($sheet)
     {
         $this->sheet = $sheet;
+        return $this;
+    }
+
+    public function hasHeader($hasHeaderRow)
+    {
+        $this->hasHeaderRow = $hasHeaderRow;
     }
 
     public function setParser(ParserInterface $parser)
     {
         $this->parser = $parser;
+        return $this;
+    }
+
+    public function setModel(Model $model)
+    {
+        $this->model = $model;
+        return $this;
     }
 
     abstract public function getType();
 
+    abstract public function createReader();
+
     public function getCollection()
     {
-        $reader = $this->create();
-        $reader->open();
-        $collection = $this->parseRows($reader);
+        $headers = false;
+
+        $reader = $this->open();
+
+        foreach ($reader->getSheetIterator() as $index => $sheet) {
+            if ($index !== $this->sheet) {
+                continue;
+            }
+
+            $collection = $this->model ? $this->model->newCollection() : collect([]);
+
+            foreach ($sheet->getRowIterator() as $rowindex => $row) {
+                if ($rowindex == 1 && $this->hasHeaderRow) {
+                    $headers = $row->toArray();
+                } else {
+                    $data = $this->parser->transform($row->toArray(), $headers);
+
+                    if ($data !== false) {
+                        if ($this->model) {
+                            $data = $this->model->getQuery()->newInstance($data);
+                        }
+
+                        $collection->push($data);
+                    }
+                }
+            }
+        }
+
         $reader->close();
+
         return $collection;
     }
 
-    protected function create()
+    public function save($updateIfEquals = [])
     {
-        return ReaderFactory::create($this->type);
-    }
+        if (!$this->model) {
+            return;
+        }
+
+        $headers = false;
+
+        $reader = $this->open();
+
+        $updateIfEquals = array_flip($updateIfEquals);
 
-    protected function parseRows($reader)
-    {
-        $collection = [];
         foreach ($reader->getSheetIterator() as $index => $sheet) {
             if ($index !== $this->sheet) {
                 continue;
             }
-            foreach ($sheet->getRowIterator() as $row) {
-                $collection[] = $this->parser->getData($row);
+
+            foreach ($sheet->getRowIterator() as $rowindex => $row) {
+                if ($rowindex == 1 && $this->hasHeaderRow) {
+                    $headers = $row->toArray();
+                } else {
+                    $data = $this->parser->transform($row->toArray(), $headers);
+                    if ($data !== false) {
+                        $relationships = [];
+                        $when = array_intersect_key($data, $updateIfEquals);
+                        $values = array_diff_key($data, $when);
+
+                        foreach ($values as $key => $val) {
+                            if (method_exists($this->model, $key)) {
+                                unset($values[$key]);
+                                $relationships[$key] = $val;
+                            }
+                        }
+
+                        if (!empty($when)) {
+                            $this->model->getQuery()->updateOrInsert($when, $values);
+                        } else {
+                            $this->model->getQuery()->insert($values);
+                        }
+
+                        if (count($relationships)) {
+                            $model = $this->model->where($values)
+                                ->orderBy($this->model->getKeyName(), 'desc')
+                                ->first();
+                            foreach ($relationships as $key => $val) {
+                                if (is_array($val)) {
+                                    $model->{$key}()->createMany($val);
+                                } else {
+                                    $model->{$key}()->associate($val);
+                                }
+                            }
+                        }
+                    }
+                }
             }
         }
-        return collect($collection);
+    }
+
+    protected function open()
+    {
+        $reader = $this->createReader();
+        $reader->open($this->path);
+        $this->callbacks->each(function ($elem) use (&$writer) {
+            call_user_func_array(array($writer, $elem[0]), $elem[1]);
+        });
+        return $reader;
     }
 }
diff --git a/src/Importer/Csv.php b/src/Importer/Csv.php
index f91e380..dc23e4d 100644
--- a/src/Importer/Csv.php
+++ b/src/Importer/Csv.php
@@ -2,6 +2,7 @@
 namespace Cyberduck\LaravelExcel\Importer;
 
 use Box\Spout\Common\Type;
+use Box\Spout\Reader\Common\Creator\ReaderEntityFactory;
 
 class Csv extends AbstractSpreadsheet
 {
@@ -9,4 +10,9 @@ public function getType()
     {
         return Type::CSV;
     }
+
+    public function createReader()
+    {
+        return ReaderEntityFactory::createCSVReader();
+    }
 }
diff --git a/src/Importer/Excel.php b/src/Importer/Excel.php
index b5e51b9..6389825 100644
--- a/src/Importer/Excel.php
+++ b/src/Importer/Excel.php
@@ -2,6 +2,7 @@
 namespace Cyberduck\LaravelExcel\Importer;
 
 use Box\Spout\Common\Type;
+use Box\Spout\Reader\Common\Creator\ReaderEntityFactory;
 
 class Excel extends AbstractSpreadsheet
 {
@@ -9,4 +10,9 @@ public function getType()
     {
         return Type::XLSX;
     }
+
+    public function createReader()
+    {
+        return ReaderEntityFactory::createXLSXReader();
+    }
 }
diff --git a/src/Importer/OpenOffice.php b/src/Importer/OpenOffice.php
index abd2b3e..b936d39 100644
--- a/src/Importer/OpenOffice.php
+++ b/src/Importer/OpenOffice.php
@@ -2,6 +2,7 @@
 namespace Cyberduck\LaravelExcel\Importer;
 
 use Box\Spout\Common\Type;
+use Box\Spout\Reader\Common\Creator\ReaderEntityFactory;
 
 class OpenOffice extends AbstractSpreadsheet
 {
@@ -9,4 +10,9 @@ public function getType()
     {
         return Type::ODS;
     }
+
+    public function createReader()
+    {
+        return ReaderEntityFactory::createODSReader();
+    }
 }
diff --git a/src/Parser/BasicParser.php b/src/Parser/BasicParser.php
index 86824e3..bc179b6 100644
--- a/src/Parser/BasicParser.php
+++ b/src/Parser/BasicParser.php
@@ -1,12 +1,21 @@
 <?php
 namespace Cyberduck\LaravelExcel\Parser;
 
-use Illuminate\Database\Eloquent\Model;
+use RuntimeException;
+use Cyberduck\LaravelExcel\Contract\ParserInterface;
 
 class BasicParser implements ParserInterface
 {
-    public function getData($row)
+    public function transform($row, $header)
     {
+        if ($header) {
+            $row = array_combine($header, $row);
+
+            if ($row == false) {
+                throw new RuntimeException('Unvalid header');
+            }
+        }
+
         return $row;
     }
 }
diff --git a/src/Serialiser/BasicSerialiser.php b/src/Serialiser/BasicSerialiser.php
index 797de10..e3c73d2 100644
--- a/src/Serialiser/BasicSerialiser.php
+++ b/src/Serialiser/BasicSerialiser.php
@@ -6,9 +6,15 @@
 
 class BasicSerialiser implements SerialiserInterface
 {
-    public function getData(Model $data)
+    public function getData($data)
     {
-        return $data->toArray();
+        if ($data instanceof Model) {
+            return $data->toArray();
+        } elseif (is_array($data)) {
+            return $data;
+        } else {
+            return get_object_vars($data);
+        }
     }
 
     public function getHeaderRow()
diff --git a/tests/TestCase.php b/tests/TestCase.php
new file mode 100644
index 0000000..7514f6e
--- /dev/null
+++ b/tests/TestCase.php
@@ -0,0 +1,61 @@
+<?php
+
+use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
+
+class TestCase extends BaseTestCase
+{
+    protected $baseUrl = 'http://localhost';
+
+    protected $defaultRow = [
+        'field1' => 'A',
+        'field2' => 'B',
+        'field3' => 'C',
+        'field4' => 'D',
+        'field5' => 'E',
+        'field6' => 'F',
+        'field7' => 'G',
+        'field8' => 'H',
+        'field9' => 'I',
+        'field10' => 'J',
+        'field11' => 'K',
+        'field12' => 'L',
+        'field13' => 'M',
+        'field14' => 'N',
+        'field15' => 'O',
+    ];
+
+    public function createApplication()
+    {
+        $app = require __DIR__.'/../vendor/laravel/laravel/bootstrap/app.php';
+        $app->register('Cyberduck\LaravelExcel\ExcelServiceProvider');
+
+        $app->make('Illuminate\Contracts\Console\Kernel')->bootstrap();
+
+        return $app;
+    }
+
+    /**
+     * Setup DB before each test.
+     *
+     * @return void
+     */
+    public function setUp() : void
+    {
+        parent::setUp();
+
+        $this->app['config']->set('database.default', 'sqlite');
+        $this->app['config']->set('database.connections.sqlite.database', ':memory:');
+    }
+
+    public function seed($item = 10)
+    {
+        for ($j = 0; $j<ceil($item/50); $j++) {
+            $rows = [];
+            $limit = ($j>floor($item/50)) ? 50 : ($item-($j*50));
+            for ($i = 0; $i<$limit; $i++) {
+                $rows[] = $this->defaultRow;
+            }
+            DB::table('items')->insert($rows);
+        }
+    }
+}
diff --git a/tests/Unit/ExporterTest.php b/tests/Unit/ExporterTest.php
new file mode 100644
index 0000000..4da2c9c
--- /dev/null
+++ b/tests/Unit/ExporterTest.php
@@ -0,0 +1,176 @@
+<?php
+
+use Box\Spout\Reader\Common\Creator\ReaderEntityFactory;
+
+class ExporterTest extends TestCase
+{
+    const FILE = __DIR__.'/../docs/test.xlsx';
+
+    public function setUp() : void
+    {
+        parent::setUp();
+        $this->file = __DIR__.'/../docs/test.xlsx';
+        (new Migration)->up();
+    }
+
+    public function tearDown() : void
+    {
+        (new Migration)->down();
+        parent::tearDown();
+    }
+
+    public function test_can_export_csv()
+    {
+        $itemsToSeed = 2;
+        $this->seed($itemsToSeed);
+
+        //Export the file
+        $exporter = $this->app->make('cyber-duck/exporter')->make('csv');
+        $exporter->load(Item::all())->save(self::FILE);
+
+        //Read the content
+        $lines = 0;
+        $reader = ReaderEntityFactory::createCSVReader();
+        $reader->open($this->file);
+        foreach ($reader->getSheetIterator() as $index => $sheet) {
+            foreach ($sheet->getRowIterator() as $row) {
+                $this->assertEquals(array_values($this->defaultRow), $row->toArray());
+                $lines++;
+            }
+        }
+        $reader->close();
+        $this->assertEquals($itemsToSeed, $lines);
+
+        unlink(self::FILE);
+    }
+
+    public function test_can_export_ods()
+    {
+        $itemsToSeed = 2;
+        $this->seed($itemsToSeed);
+
+        //Export the file
+        $exporter = $this->app->make('cyber-duck/exporter')->make('openoffice');
+        $exporter->load(Item::all())->save(self::FILE);
+
+        //Read the content
+        $lines = 0;
+        $reader = ReaderEntityFactory::createODSReader();
+        $reader->open($this->file);
+        foreach ($reader->getSheetIterator() as $index => $sheet) {
+            foreach ($sheet->getRowIterator() as $row) {
+                $this->assertEquals(array_values($this->defaultRow), $row->toArray());
+                $lines++;
+            }
+        }
+        $reader->close();
+        $this->assertEquals($itemsToSeed, $lines);
+
+        unlink(self::FILE);
+    }
+
+    public function test_can_export_xlsx()
+    {
+        $itemsToSeed = 2;
+        $this->seed($itemsToSeed);
+
+        //Export the file
+        $exporter = $this->app->make('cyber-duck/exporter')->make('excel');
+        $exporter->load(Item::all())->save(self::FILE);
+
+        //Read the content
+        $lines = 0;
+        $reader = ReaderEntityFactory::createXLSXReader();
+        $reader->open($this->file);
+        foreach ($reader->getSheetIterator() as $index => $sheet) {
+            foreach ($sheet->getRowIterator() as $row) {
+                $this->assertEquals(array_values($this->defaultRow), $row->toArray());
+                $lines++;
+            }
+        }
+        $reader->close();
+        $this->assertEquals($itemsToSeed, $lines);
+
+        unlink(self::FILE);
+    }
+
+    public function test_can_use_a_query_builder()
+    {
+        $itemsToSeed = 2;
+        $this->seed($itemsToSeed);
+
+        //Export the file
+        $exporter = $this->app->make('cyber-duck/exporter')->make('csv');
+        $exporter->loadQuery(Item::getQuery())->save(self::FILE);
+
+        //Read the content
+        $lines = 0;
+        $reader = ReaderEntityFactory::createCSVReader();
+        $reader->open($this->file);
+        foreach ($reader->getSheetIterator() as $index => $sheet) {
+            foreach ($sheet->getRowIterator() as $idx => $row) {
+                $expected = array_merge([strval($idx)], array_values($this->defaultRow));
+                $this->assertEquals($expected, $row->toArray());
+                $lines++;
+            }
+        }
+        $reader->close();
+        $this->assertEquals($itemsToSeed, $lines);
+
+        unlink(self::FILE);
+    }
+
+    public function test_can_use_a_query_builder_with_chunk()
+    {
+        $itemsToSeed = 2;
+        $this->seed($itemsToSeed);
+
+        //Export the file
+        $exporter = $this->app->make('cyber-duck/exporter')->make('csv');
+        $exporter->loadQuery(Item::getQuery())->setChunk(2)->save(self::FILE);
+
+        //Read the content
+        $lines = 0;
+        $reader = ReaderEntityFactory::createCSVReader();
+        $reader->open($this->file);
+        foreach ($reader->getSheetIterator() as $index => $sheet) {
+            foreach ($sheet->getRowIterator() as $idx => $row) {
+                $expected = array_merge([strval($idx)], array_values($this->defaultRow));
+                $this->assertEquals($expected, $row->toArray());
+                $lines++;
+            }
+        }
+        $reader->close();
+        $this->assertEquals($itemsToSeed, $lines);
+
+        unlink(self::FILE);
+    }
+
+    public function test_can_use_a_custom_serialiser()
+    {
+        $itemsToSeed = 2;
+        $this->seed($itemsToSeed);
+
+        //Export the file
+        $exporter = $this->app->make('cyber-duck/exporter')->make('csv');
+        $exporter->setSerialiser(new FirstColumnOnlySerialiser())->load(Item::all())->save(self::FILE);
+
+        //Read the content
+        $lines = 0;
+        $reader = ReaderEntityFactory::createCSVReader();
+        $reader->open($this->file);
+        foreach ($reader->getSheetIterator() as $index => $sheet) {
+            foreach ($sheet->getRowIterator() as $row) {
+                if ($lines == 0) {
+                    $this->assertEquals(['HEADER'], $row->toArray());
+                } else {
+                    $this->assertEquals(['A'], $row->toArray());
+                }
+                $lines++;
+            }
+        }
+        $reader->close();
+
+        unlink(self::FILE);
+    }
+}
diff --git a/tests/Unit/FacadesTest.php b/tests/Unit/FacadesTest.php
new file mode 100644
index 0000000..2ad9024
--- /dev/null
+++ b/tests/Unit/FacadesTest.php
@@ -0,0 +1,16 @@
+<?php
+
+class ExporterFacadeTest extends TestCase
+{
+    public function test_facades_are_available()
+    {
+        $this->assertInstanceOf(
+            \Cyberduck\LaravelExcel\Factory\ExporterFactory::class,
+            Exporter::getFacadeRoot()
+        );
+        $this->assertInstanceOf(
+            \Cyberduck\LaravelExcel\Factory\ImporterFactory::class,
+            Importer::getFacadeRoot()
+        );
+    }
+}
diff --git a/tests/Unit/FactoryTest.php b/tests/Unit/FactoryTest.php
new file mode 100644
index 0000000..55b7ebd
--- /dev/null
+++ b/tests/Unit/FactoryTest.php
@@ -0,0 +1,90 @@
+<?php
+
+use Cyberduck\LaravelExcel\Factory\ImporterFactory;
+use Cyberduck\LaravelExcel\Factory\ExporterFactory;
+
+class ImporterFactoryTest extends TestCase
+{
+    public function test_factory_can_create_csv()
+    {
+        $factory = new ImporterFactory();
+        $spreadsheet = $factory->make('csv');
+        $this->assertInstanceOf(
+            \Cyberduck\LaravelExcel\Importer\Csv::class,
+            $spreadsheet
+        );
+        $this->assertEquals(
+            \Box\Spout\Common\Type::CSV,
+            $spreadsheet->getType()
+        );
+    }
+
+    public function test_factory_can_create_odt()
+    {
+        $factory = new ImporterFactory();
+        $spreadsheet = $factory->make('openoffice');
+        $this->assertInstanceOf(
+            \Cyberduck\LaravelExcel\Importer\OpenOffice::class,
+            $factory->make('openoffice')
+        );
+        $this->assertEquals(
+            \Box\Spout\Common\Type::ODS,
+            $spreadsheet->getType()
+        );
+    }
+
+    public function test_factory_can_create_xls()
+    {
+        $factory = new ImporterFactory();
+        $spreadsheet = $factory->make('excel');
+        $this->assertInstanceOf(
+            \Cyberduck\LaravelExcel\Importer\Excel::class,
+            $factory->make('excel')
+        );
+        $this->assertEquals(
+            \Box\Spout\Common\Type::XLSX,
+            $spreadsheet->getType()
+        );
+    }
+    public function test_exporter_factory_can_create_csv()
+    {
+        $factory = new ExporterFactory();
+        $spreadsheet = $factory->make('csv');
+        $this->assertInstanceOf(
+            \Cyberduck\LaravelExcel\Exporter\Csv::class,
+            $spreadsheet
+        );
+        $this->assertEquals(
+            \Box\Spout\Common\Type::CSV,
+            $spreadsheet->getType()
+        );
+    }
+
+    public function test_exporter_factory_can_create_odt()
+    {
+        $factory = new ExporterFactory();
+        $spreadsheet = $factory->make('openoffice');
+        $this->assertInstanceOf(
+            \Cyberduck\LaravelExcel\Exporter\OpenOffice::class,
+            $spreadsheet
+        );
+        $this->assertEquals(
+            \Box\Spout\Common\Type::ODS,
+            $spreadsheet->getType()
+        );
+    }
+
+    public function test_exporter_factory_can_create_xls()
+    {
+        $factory = new ExporterFactory();
+        $spreadsheet = $factory->make('excel');
+        $this->assertInstanceOf(
+            \Cyberduck\LaravelExcel\Exporter\Excel::class,
+            $spreadsheet
+        );
+        $this->assertEquals(
+            \Box\Spout\Common\Type::XLSX,
+            $spreadsheet->getType()
+        );
+    }
+}
diff --git a/tests/Unit/ImporterTest.php b/tests/Unit/ImporterTest.php
new file mode 100644
index 0000000..72b2e39
--- /dev/null
+++ b/tests/Unit/ImporterTest.php
@@ -0,0 +1,7 @@
+<?php
+
+use Cyberduck\LaravelExcel\Factory\ImporterFactory;
+
+abstract class ImporterTest extends TestCase
+{
+}
diff --git a/tests/Unit/ServiceProviderTest.php b/tests/Unit/ServiceProviderTest.php
new file mode 100644
index 0000000..b8177f6
--- /dev/null
+++ b/tests/Unit/ServiceProviderTest.php
@@ -0,0 +1,28 @@
+<?php
+
+class ExcelServiceProviderTest extends TestCase
+{
+    public function test_service_provider()
+    {
+        //Test services
+        $this->assertTrue($this->app->bound('cyber-duck/exporter'));
+        $this->assertTrue($this->app->bound('cyber-duck/importer'));
+        $this->assertInstanceOf(
+            \Cyberduck\LaravelExcel\Factory\ExporterFactory::class,
+            $this->app->make('cyber-duck/exporter')
+        );
+        $this->assertInstanceOf(
+            \Cyberduck\LaravelExcel\Factory\ImporterFactory::class,
+            $this->app->make('cyber-duck/importer')
+        );
+        //Test aliases
+        $this->assertInstanceOf(
+            \Cyberduck\LaravelExcel\Exporter\AbstractSpreadsheet::class,
+            Exporter::make("Excel")
+        );
+        $this->assertInstanceOf(
+            \Cyberduck\LaravelExcel\Importer\AbstractSpreadsheet::class,
+            Importer::make("Excel")
+        );
+    }
+}
diff --git a/tests/docs/.gitignore b/tests/docs/.gitignore
new file mode 100644
index 0000000..c96a04f
--- /dev/null
+++ b/tests/docs/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
\ No newline at end of file
diff --git a/tests/utils/DatabaseSeeder.php b/tests/utils/DatabaseSeeder.php
new file mode 100644
index 0000000..c5eb6f8
--- /dev/null
+++ b/tests/utils/DatabaseSeeder.php
@@ -0,0 +1,34 @@
+<?php
+
+use Illuminate\Database\Seeder;
+use Illuminate\Database\Eloquent\Model;
+
+class DatabaseSeeder extends Seeder
+{
+    public function run()
+    {
+        for ($j = 0; $j<1000; $j++) {
+            $rows = [];
+            for ($i = 0; $i<50; $i++) {
+                $rows[] = [
+                    'field1' => 'A',
+                    'field2' => 'B',
+                    'field3' => 'C',
+                    'field4' => 'D',
+                    'field5' => 'E',
+                    'field6' => 'F',
+                    'field7' => 'G',
+                    'field8' => 'H',
+                    'field9' => 'I',
+                    'field10' => 'J',
+                    'field11' => 'K',
+                    'field12' => 'L',
+                    'field13' => 'M',
+                    'field14' => 'N',
+                    'field15' => 'O',
+                ];
+            }
+            DB::table('items')->insert($rows);
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/utils/FirstColumnOnlySerialiser.php b/tests/utils/FirstColumnOnlySerialiser.php
new file mode 100644
index 0000000..108a6c1
--- /dev/null
+++ b/tests/utils/FirstColumnOnlySerialiser.php
@@ -0,0 +1,17 @@
+<?php
+
+use Cyberduck\LaravelExcel\Contract\SerialiserInterface;
+
+class FirstColumnOnlySerialiser implements SerialiserInterface
+{
+    public function getData($data)
+    {
+        $arrayValues = $data->toArray();
+        return [$arrayValues['field1']];
+    }
+
+    public function getHeaderRow()
+    {
+        return ['HEADER'];
+    }
+}
diff --git a/tests/utils/Item.php b/tests/utils/Item.php
new file mode 100644
index 0000000..d52b569
--- /dev/null
+++ b/tests/utils/Item.php
@@ -0,0 +1,8 @@
+<?php
+
+use Illuminate\Database\Eloquent\Model;
+
+class Item extends Model
+{
+    protected $hidden = ['id'];
+}
diff --git a/tests/utils/Migration.php b/tests/utils/Migration.php
new file mode 100644
index 0000000..b007732
--- /dev/null
+++ b/tests/utils/Migration.php
@@ -0,0 +1,44 @@
+<?php
+
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Database\Migrations\Migration as BaseMigration;
+
+class Migration extends BaseMigration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::create('items', function (Blueprint $table) {
+            $table->increments('id');
+            $table->text('field1');
+            $table->text('field2');
+            $table->text('field3');
+            $table->text('field4');
+            $table->text('field5');
+            $table->text('field6');
+            $table->text('field7');
+            $table->text('field8');
+            $table->text('field9');
+            $table->text('field10');
+            $table->text('field11');
+            $table->text('field12');
+            $table->text('field13');
+            $table->text('field14');
+            $table->text('field15');
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::drop('items');
+    }
+}