Skip to content

Commit

Permalink
Added tests for args/kwargs and also added docs fr it
Browse files Browse the repository at this point in the history
  • Loading branch information
robdox committed Jul 5, 2018
1 parent 4c103e8 commit 720e58a
Show file tree
Hide file tree
Showing 4 changed files with 168 additions and 56 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ dist/
bin
include
lib
db.sqlite3

.DS_Store

Expand Down
168 changes: 112 additions & 56 deletions docs/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,65 +3,13 @@ id: usage
title: Usage
---

Example Django Model located at bottom of page.

## Example Django Model

```python


from django.db import models
from .options import COLORS, SIZES, SHAPES
from ScopingMixin import ScopingMixin, ScopingQuerySet
import datetime


class Widget(ScopingMixin, models.Model):
name = models.CharField(max_length=30)
color = models.CharField(choices=COLORS, max_length=30)
size = models.CharField(choices=SIZES, max_length=30)
shape = models.CharField(choices=SHAPES, max_length=30)
used_on = models.DateField(default=datetime.date.today)

objects = ScopingQuerySet.as_manager()


def get_name(self):
return self.name

def get_color(self):
return self.color

def get_size(self):
return self.size

def get_shape(self):
return self.shape
## Basic Usage

def get_used_on(self):
return self.used_on

# Scopes for filtering
Widget.scope('basic_filter_widget', lambda qs: qs.f(color='blue',
size='small',
shape='circle'))
Widget.scope('blue', lambda qs: qs.f(color='blue'))
Widget.scope('small', lambda qs: qs.f(size='small'))
Widget.scope('circle', lambda qs: qs.f(shape='circle'))
Widget.scope('before_y2k', lambda qs: qs.f(used_on__lte=datetime.date(2000,1,1)))

# Scopes for excluding
Widget.scope('basic_exclude_widget', lambda qs: qs.e(color='blue',
size='small',
shape='circle'))
Widget.scope('not_blue', lambda qs: qs.e(color='blue'))
Widget.scope('not_small', lambda qs: qs.e(size='small'))
Widget.scope('not_circle', lambda qs: qs.e(shape='circle'))
Widget.scope('not_before_y2k', lambda qs: qs.e(used_on__lte=datetime.date(2000,1,1)))
```

## Usage

### Basic Scoping
### Scoping

Now, Let's say we wanted to find all of the widgets in our database which were
blue.
Expand All @@ -76,7 +24,7 @@ With easy scoping:
Widget.a().blue()
```

### Basic Scoping Multiple Fields
### Scoping Multiple Fields
How about finding all of the widgets which are blue, small, and a circle.

Without easy scoping:
Expand Down Expand Up @@ -144,3 +92,111 @@ alphabetical order.
```python
Widget.a().blue().small().not_circle().order_by('color')
```

## Advanced Usage

Using lambda functions, and that scopes take *args, **kwargs, you can create
some really interesting scopes to simply your workflow.

### Arguments

You could have a scope that filters on colors but instead of having one for
`blue` and one for `green` we can just have do something like this.

```python
Widget.scope('colors', lambda queryset, value: queryset.f(color=value))
# Then this works for any color
Widget.a().color('blue')
```

### Multiple Arguments

You can also make scopes on more than one argument, let's check out one for
color and size

```python
Widget.scope('color_size', lambda queryset, c_value, s_value: queryset.f(color=value, size=s_value))
# Then you can just pass like this
Widget.a().color_size('blue', 'small')
```

### Keyword Arguments

The problem with args is that you have to remember the order you set up when you
defined the scope. You can just use kwargs instead!

```python
Widget.scope('foo', lambda queryset, **kwargs: queryset.f(**kwargs))
# Then this works for any color
Widget.a().foo(color='blue')
```

### Multiple Keyword Arguments

With this you can just go nuts on filtering, but this is basically just using
the actual `.filter()` method.

```python
Widget.scope('foo', lambda queryset, **kwargs: queryset.f(**kwargs))
# Then this works for any color
Widget.a().foo(color='blue', size='small')
```





## Example Django Model

```python


from django.db import models
from .options import COLORS, SIZES, SHAPES
from ScopingMixin import ScopingMixin, ScopingQuerySet
import datetime


class Widget(ScopingMixin, models.Model):
name = models.CharField(max_length=30)
color = models.CharField(choices=COLORS, max_length=30)
size = models.CharField(choices=SIZES, max_length=30)
shape = models.CharField(choices=SHAPES, max_length=30)
used_on = models.DateField(default=datetime.date.today)

objects = ScopingQuerySet.as_manager()


def get_name(self):
return self.name

def get_color(self):
return self.color

def get_size(self):
return self.size

def get_shape(self):
return self.shape

def get_used_on(self):
return self.used_on

# Scopes for filtering
Widget.scope('basic_filter_widget', lambda qs: qs.f(color='blue',
size='small',
shape='circle'))
Widget.scope('blue', lambda qs: qs.f(color='blue'))
Widget.scope('small', lambda qs: qs.f(size='small'))
Widget.scope('circle', lambda qs: qs.f(shape='circle'))
Widget.scope('before_y2k', lambda qs: qs.f(used_on__lte=datetime.date(2000,1,1)))

# Scopes for excluding
Widget.scope('basic_exclude_widget', lambda qs: qs.e(color='blue',
size='small',
shape='circle'))
Widget.scope('not_blue', lambda qs: qs.e(color='blue'))
Widget.scope('not_small', lambda qs: qs.e(size='small'))
Widget.scope('not_circle', lambda qs: qs.e(shape='circle'))
Widget.scope('not_before_y2k', lambda qs: qs.e(used_on__lte=datetime.date(2000,1,1)))
```
50 changes: 50 additions & 0 deletions easy_scoping/tests/test_scoping.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,56 @@ def test_db_data_loaded(self):
obj = obj.a()
self.assertEqual(obj.count(), 336)

def test_passing_many_kwargs(self):
obj1 = Widget.objects.filter(color='blue',
size='small')
obj2 = Widget.a().take_kwargs(color='blue', size='small')

self.assertQuerysetEqual(obj1,
obj2,
transform=lambda x: x,
ordered=False)
self.assertEqual(obj1.count(), obj2.count())

obj3 = Widget.a().take_kwargs(size='small', color='blue')

self.assertQuerysetEqual(obj1,
obj3,
transform=lambda x: x,
ordered=False)
self.assertEqual(obj1.count(), obj3.count())

def test_passing_kwargs(self):
obj1 = Widget.objects.filter(color='blue')
obj2 = Widget.a().take_kwargs(color='blue')

self.assertQuerysetEqual(obj1,
obj2,
transform=lambda x: x,
ordered=False)
self.assertEqual(obj1.count(), obj2.count())

def test_passing_many_args(self):
obj1 = Widget.objects.filter(color='blue',
size='small')
obj2 = Widget.a().take_more_args('blue', 'small')

self.assertQuerysetEqual(obj1,
obj2,
transform=lambda x: x,
ordered=False)
self.assertEqual(obj1.count(), obj2.count())

def test_passing_args(self):
obj1 = Widget.objects.filter(color='blue')
obj2 = Widget.a().take_args('blue')

self.assertQuerysetEqual(obj1,
obj2,
transform=lambda x: x,
ordered=False)
self.assertEqual(obj1.count(), obj2.count())

def test_no_scope_registered(self):
with self.assertRaises(AttributeError):
Widget.a().not_a_scope()
Expand Down
5 changes: 5 additions & 0 deletions easy_scoping/widgets/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,8 @@ def get_used_on(self):
Widget.scope('not_circle', lambda qs: qs.e(shape='circle'))
Widget.scope('not_before_y2k', lambda qs: qs.e(used_on__lte=datetime.date(2000,1,1)))
Widget.scope('not_after_y2k', lambda qs: qs.e(used_on__gte=datetime.date(2000,1,1)))

# Scope takes argument
Widget.scope('take_args', lambda qs, i: qs.f(color=i))
Widget.scope('take_more_args', lambda qs, i, r: qs.f(color=i, size=r))
Widget.scope('take_kwargs', lambda qs, **kwargs: qs.f(**kwargs))

0 comments on commit 720e58a

Please sign in to comment.