Skip to content

Commit 269d44c

Browse files
author
Andrew Brookins
committed
Final docs push
1 parent 321b356 commit 269d44c

File tree

13 files changed

+442
-48
lines changed

13 files changed

+442
-48
lines changed

README.md

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ andrew = Customer(
113113
# The model generates a globally unique primary key automatically
114114
# without needing to talk to Redis.
115115
print(andrew.pk)
116-
# > '01FJM6PH661HCNNRC884H6K30C'
116+
# > "01FJM6PH661HCNNRC884H6K30C"
117117

118118
# We can save the model to Redis by calling `save()`:
119119
andrew.save()
@@ -199,7 +199,6 @@ from redis_om import (
199199
HashModel,
200200
Migrator
201201
)
202-
from redis_om import get_redis_connection
203202

204203

205204
class Customer(HashModel):
@@ -217,8 +216,7 @@ class Customer(HashModel):
217216
# Before running queries, we need to run migrations to set up the
218217
# indexes that Redis OM will use. You can also use the `migrate`
219218
# CLI tool for this!
220-
redis = get_redis_connection()
221-
Migrator(redis).run()
219+
Migrator().run()
222220

223221
# Find all customers with the last name "Brookins"
224222
Customer.find(Customer.last_name == "Brookins").all()
@@ -253,7 +251,6 @@ from redis_om import (
253251
Field,
254252
Migrator,
255253
)
256-
from redis_om import get_redis_connection
257254

258255

259256
class Address(EmbeddedJsonModel):
@@ -284,8 +281,7 @@ class Customer(JsonModel):
284281
# Before running queries, we need to run migrations to set up the
285282
# indexes that Redis OM will use. You can also use the `migrate`
286283
# CLI tool for this!
287-
redis = get_redis_connection()
288-
Migrator(redis).run()
284+
Migrator().run()
289285

290286
# Find all customers who live in San Antonio, TX
291287
Customer.find(Customer.address.city == "San Antonio",

aredis_om/model/cli/migrate.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
@click.option("--module", default="aredis_om")
88
def migrate(module):
99
migrator = Migrator(module)
10+
migrator.detect_migrations()
1011

1112
if migrator.migrations:
1213
print("Pending migrations:")

aredis_om/model/encoders.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,15 @@ def jsonable_encoder(
6868
include = set(include)
6969
if exclude is not None and not isinstance(exclude, (set, dict)):
7070
exclude = set(exclude)
71+
72+
if custom_encoder:
73+
if type(obj) in custom_encoder:
74+
return custom_encoder[type(obj)](obj)
75+
else:
76+
for encoder_type, encoder in custom_encoder.items():
77+
if isinstance(obj, encoder_type):
78+
return encoder(obj)
79+
7180
if isinstance(obj, BaseModel):
7281
encoder = getattr(obj.__config__, "json_encoders", {})
7382
if custom_encoder:
@@ -145,13 +154,9 @@ def jsonable_encoder(
145154
)
146155
return encoded_list
147156

148-
if custom_encoder:
149-
if type(obj) in custom_encoder:
150-
return custom_encoder[type(obj)](obj)
151-
else:
152-
for encoder_type, encoder in custom_encoder.items():
153-
if isinstance(obj, encoder_type):
154-
return encoder(obj)
157+
# This function originally called custom encoders here,
158+
# which meant we couldn't override the encoder for many
159+
# types hard-coded into this function (lists, etc.).
155160

156161
if type(obj) in ENCODERS_BY_TYPE:
157162
return ENCODERS_BY_TYPE[type(obj)](obj)

aredis_om/model/migrations/migrator.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,11 @@ async def drop(self):
8484

8585

8686
class Migrator:
87-
def __init__(self, redis: Redis, module=None):
87+
def __init__(self, module=None):
8888
self.module = module
8989
self.migrations: List[IndexMigration] = []
90-
self.redis = redis
9190

92-
async def run(self):
91+
async def detect_migrations(self):
9392
# Try to load any modules found under the given path or module name.
9493
if self.module:
9594
import_submodules(self.module)
@@ -100,6 +99,7 @@ async def run(self):
10099

101100
for name, cls in model_registry.items():
102101
hash_key = schema_hash_key(cls.Meta.index_name)
102+
redis = cls.db()
103103
try:
104104
schema = cls.redisearch_schema()
105105
except NotImplementedError:
@@ -108,7 +108,7 @@ async def run(self):
108108
current_hash = hashlib.sha1(schema.encode("utf-8")).hexdigest() # nosec
109109

110110
try:
111-
await self.redis.execute_command("ft.info", cls.Meta.index_name)
111+
await redis.execute_command("ft.info", cls.Meta.index_name)
112112
except ResponseError:
113113
self.migrations.append(
114114
IndexMigration(
@@ -117,12 +117,12 @@ async def run(self):
117117
schema,
118118
current_hash,
119119
MigrationAction.CREATE,
120-
self.redis,
120+
redis,
121121
)
122122
)
123123
continue
124124

125-
stored_hash = await self.redis.get(hash_key)
125+
stored_hash = await redis.get(hash_key)
126126
schema_out_of_date = current_hash != stored_hash
127127

128128
if schema_out_of_date:
@@ -134,7 +134,7 @@ async def run(self):
134134
schema,
135135
current_hash,
136136
MigrationAction.DROP,
137-
self.redis,
137+
redis,
138138
stored_hash,
139139
)
140140
)
@@ -145,12 +145,14 @@ async def run(self):
145145
schema,
146146
current_hash,
147147
MigrationAction.CREATE,
148-
self.redis,
148+
redis,
149149
stored_hash,
150150
)
151151
)
152152

153+
async def run(self):
153154
# TODO: Migration history
154155
# TODO: Dry run with output
156+
await self.detect_migrations()
155157
for migration in self.migrations:
156158
await migration.run()

aredis_om/model/model.py

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ def embedded(cls):
107107

108108

109109
def is_supported_container_type(typ: Optional[type]) -> bool:
110+
# TODO: Wait, why don't we support indexing sets?
110111
if typ == list or typ == tuple:
111112
return True
112113
unwrapped = get_origin(typ)
@@ -479,8 +480,7 @@ def expand_tag_value(value):
479480
if isinstance(value, str):
480481
return escaper.escape(value)
481482
if isinstance(value, bytes):
482-
# TODO: We don't decode and then escape bytes objects passed as input.
483-
# Should we?
483+
# TODO: We don't decode bytes objects passed as input. Should we?
484484
# TODO: TAG indexes fail on JSON arrays of numbers -- only strings
485485
# are allowed -- what happens if we save an array of bytes?
486486
return value
@@ -966,15 +966,14 @@ class PrimaryKey:
966966
field: ModelField
967967

968968

969-
class BaseMeta(abc.ABC):
969+
class BaseMeta(Protocol):
970970
global_key_prefix: str
971971
model_key_prefix: str
972972
primary_key_pattern: str
973973
database: aioredis.Redis
974974
primary_key: PrimaryKey
975975
primary_key_creator_cls: Type[PrimaryKeyCreator]
976976
index_name: str
977-
abstract: bool
978977
embedded: bool
979978
encoding: str
980979

@@ -994,7 +993,6 @@ class DefaultMeta:
994993
primary_key: Optional[PrimaryKey] = None
995994
primary_key_creator_cls: Optional[Type[PrimaryKeyCreator]] = None
996995
index_name: Optional[str] = None
997-
abstract: Optional[bool] = False
998996
embedded: Optional[bool] = False
999997
encoding: str = "utf-8"
1000998

@@ -1269,17 +1267,23 @@ def __init_subclass__(cls, **kwargs):
12691267
super().__init_subclass__(**kwargs)
12701268

12711269
for name, field in cls.__fields__.items():
1270+
origin = get_origin(field.outer_type_)
1271+
if origin:
1272+
for typ in (Set, Mapping, List):
1273+
if issubclass(origin, typ):
1274+
raise RedisModelError(
1275+
f"HashModels cannot index set, list,"
1276+
f" or mapping fields. Field: {name}"
1277+
)
1278+
12721279
if issubclass(field.outer_type_, RedisModel):
12731280
raise RedisModelError(
1274-
f"HashModels cannot have embedded model " f"fields. Field: {name}"
1281+
f"HashModels cannot index embedded model fields. Field: {name}"
1282+
)
1283+
elif dataclasses.is_dataclass(field.outer_type_):
1284+
raise RedisModelError(
1285+
f"HashModels cannot index dataclass fields. Field: {name}"
12751286
)
1276-
1277-
for typ in (Set, Mapping, List):
1278-
if issubclass(field.outer_type_, typ):
1279-
raise RedisModelError(
1280-
f"HashModels cannot have set, list,"
1281-
f" or mapping fields. Field: {name}"
1282-
)
12831287

12841288
async def save(self, pipeline: Optional[Pipeline] = None) -> "HashModel":
12851289
self.check()
@@ -1360,6 +1364,8 @@ def schema_for_fields(cls):
13601364
for name, field in cls.__fields__.items():
13611365
# TODO: Merge this code with schema_for_type()?
13621366
_type = field.outer_type_
1367+
is_subscripted_type = get_origin(_type)
1368+
13631369
if getattr(field.field_info, "primary_key", None):
13641370
if issubclass(_type, str):
13651371
redisearch_field = (
@@ -1372,7 +1378,12 @@ def schema_for_fields(cls):
13721378
schema_parts.append(redisearch_field)
13731379
elif getattr(field.field_info, "index", None) is True:
13741380
schema_parts.append(cls.schema_for_type(name, _type, field.field_info))
1375-
elif is_supported_container_type(_type):
1381+
elif is_subscripted_type:
1382+
# Ignore subscripted types (usually containers!) that we don't
1383+
# support, for the purposes of indexing.
1384+
if not is_supported_container_type(_type):
1385+
continue
1386+
13761387
embedded_cls = get_args(_type)
13771388
if not embedded_cls:
13781389
# TODO: Test if this can really happen.

docs/getting_started.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -658,7 +658,6 @@ from pydantic import EmailStr
658658

659659
from redis_om import (
660660
Field,
661-
get_redis_connection,
662661
HashModel,
663662
Migrator
664663
)
@@ -679,8 +678,7 @@ class Customer(HashModel):
679678
# Before running queries, we need to run migrations to set up the
680679
# indexes that Redis OM will use. You can also use the `migrate`
681680
# CLI tool for this!
682-
redis = get_redis_connection()
683-
Migrator(redis).run()
681+
Migrator().run()
684682

685683
# Find all customers with the last name "Brookins"
686684
Customer.find(Customer.last_name == "Brookins").all()

docs/index.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Redis OM for Python
22

3-
Welcome! This is the index of documentation for redis-om-python.
3+
Welcome! This is the documentation for redis-om-python.
44

55
**NOTE**: The documentation is a bit sparse at the moment but will continue to grow!
66

@@ -12,6 +12,10 @@ Read the Getting Started tutorial at [getting_started.md](getting_started.md).
1212

1313
Read about connecting to Redis at [connections.md](connections.md).
1414

15+
## Models and Fields
16+
17+
Learn all about how to create model instances and define fields in [models.md](models.md).
18+
1519
## Validating Data
1620

1721
Read about how to use Redis OM models to validate data at [validation.md](validation.md)

0 commit comments

Comments
 (0)