Navigation Menu

Skip to content

Commit

Permalink
Merged indexes and compoundIndexes into a single field in the schema
Browse files Browse the repository at this point in the history
  • Loading branch information
Marin Rusu committed Nov 15, 2019
1 parent dea0661 commit 924f92f
Show file tree
Hide file tree
Showing 10 changed files with 80 additions and 80 deletions.
1 change: 0 additions & 1 deletion .gitignore
Expand Up @@ -18,4 +18,3 @@ pouch__all_dbs__/
pouch__all_dbs__/
.DS_Store
.DS_Store?
dist/
11 changes: 5 additions & 6 deletions docs-src/rx-schema.md
Expand Up @@ -109,9 +109,7 @@ const mySchema = {


## Indexes
RxDB supports secondary indexes which are defined at the schema-level of the collection.<br>
To add a simple indexes, add them in an array to a `indexes`-field at the top-level of the schema-definition.<br>
To add compound-indexes, add them in an array to a `compoundIndexes`-field at the top-level of the schema-definition.
RxDB supports secondary indexes which are defined at the schema-level of the collection.

Index is only allowed on field types `string`, `integer` and `number`

Expand Down Expand Up @@ -145,9 +143,10 @@ const schemaWithIndexes = {
}
}
},
indexes: ['firstName', 'creditCards.[].cvc'], // <- this will create two indexes for these fields
compoundIndexes: [
['lastName', 'familyName'] // <- this will create a compound-index for these two fields
indexes: [
'firstName', // <- this will create a simple index for the `firstName` field
'creditCards.[].cvc',
['lastName', 'familyName'] // <- this will create a compound-index for these two fields
]
};
```
Expand Down
11 changes: 5 additions & 6 deletions src/plugins/error-messages.ts
Expand Up @@ -139,16 +139,15 @@ const CODES: { [k: string]: string } = {
SC15: 'SchemaCheck: primary cannot be encrypted',
SC16: 'SchemaCheck: primary must have type: string',
SC17: 'SchemaCheck: top-level fieldname is not allowed',
SC18: 'SchemaCheck: compoundIndexes must be an array',
SC19: 'SchemaCheck: compoundIndexes must contain arrays',
SC20: 'SchemaCheck: compoundIndexes.array must contains strings',
SC18: 'SchemaCheck: indexes must be an array',
SC19: 'SchemaCheck: indexes must contain strings or arrays of strings',
SC20: 'SchemaCheck: indexes.array must contain strings',
SC21: 'SchemaCheck: given index is not defined in schema',
SC22: 'SchemaCheck: given indexKey is not type:string',
SC23: 'SchemaCheck: fieldname is not allowed',
SC24: 'SchemaCheck: required fields must be set via array. See https://spacetelescope.github.io/understanding-json-schema/reference/object.html#required',
SC25: 'SchemaCheck: indexes must be an array',
SC26: 'SchemaCheck: indexes must contain strings',
SC27: 'SchemaCheck: indexes needs to be specified at collection schema level',
SC25: 'SchemaCheck: compoundIndexes needs to be specified in the indexes field',
SC26: 'SchemaCheck: indexes needs to be specified at collection schema level',

// plugins/validate.js
VD1: 'Sub-schema not found, does the schemaPath exists in your schema?',
Expand Down
70 changes: 31 additions & 39 deletions src/plugins/schema-check.ts
Expand Up @@ -254,50 +254,37 @@ export function checkSchema(jsonID: RxJsonSchema) {
}
});

// check format of jsonID.compoundIndexes
if (jsonID.compoundIndexes) {
if (!Array.isArray(jsonID.compoundIndexes)) {
throw newRxError('SC18', {
compoundIndexes: jsonID.compoundIndexes
});
}
jsonID.compoundIndexes.forEach((ar: any) => {
if (!Array.isArray(ar)) {
throw newRxError('SC19', {
compoundIndexes: jsonID.compoundIndexes
});
}

ar.forEach(str => {
if (typeof str !== 'string') {
throw newRxError('SC20', {
compoundIndexes: jsonID.compoundIndexes
});
}
});
});
}

// check format of jsonID.indexes
if (jsonID.indexes) {
// should be an array
if (!Array.isArray(jsonID.indexes)) {
throw newRxError('SC25', {
throw newRxError('SC18', {
indexes: jsonID.indexes
});
}
// should contain strings
jsonID.indexes.forEach(indexPath => {
if (typeof indexPath !== 'string') {
throw newRxError('SC26', {
indexPath
});

jsonID.indexes.forEach(index => {
// should contain strings or array of strings
if (!(typeof index === 'string' || Array.isArray(index))) {
throw newRxError('SC19', { index });
}
// if is a compound index it must contain strings
if (Array.isArray(index)) {
for (let i = 0; i < index.length; i += 1) {
if (typeof index[i] !== 'string') {
throw newRxError('SC20', { index });
}
}
}
});
}

/** TODO this check has to exist only in beta-version, to help developers migrate their schemas */
// remove backward-compatibility
// remove backward-compatibility for compoundIndexes
if (Object.keys(jsonID).includes('compoundIndexes')) {
throw newRxError('SC25');
}
// remove backward-compatibility for index: true
Object.keys(flattenObject(jsonID))
.map(key => {
// flattenObject returns only ending paths, we need all paths pointing to an object
Expand All @@ -314,21 +301,26 @@ export function checkSchema(jsonID: RxJsonSchema) {
.forEach(key => { // replace inner properties
key = key.replace('properties.', ''); // first
key = key.replace(/\.properties\./g, '.'); // middle
throw newRxError('SC27', {
indexPath: trimDots(key)
throw newRxError('SC26', {
index: trimDots(key)
});
});

// check that indexes are string or number
(jsonID.compoundIndexes || [])
.reduce((a, b) => a.concat(b), []) // break compound indexes into index parts
.concat(jsonID.indexes || [])
(jsonID.indexes || [])
.reduce((indexPaths: string[], currentIndex) => {
if (Array.isArray(currentIndex)) {
indexPaths.concat(currentIndex);
} else {
indexPaths.push(currentIndex);
}
return indexPaths;
}, [])
.filter((elem, pos, arr) => arr.indexOf(elem) === pos) // from now on working only with unique indexes
.map(indexPath => {
const realPath = getIndexRealPath(indexPath); // real path in the collection schema
const schemaObj = objectPath.get(jsonID, realPath); // get the schema of the indexed property
if (!schemaObj || typeof schemaObj !== 'object') {
throw newRxError('SC21', { indexPath });
throw newRxError('SC21', { index: indexPath });
}
return { indexPath, schemaObj };
})
Expand Down
9 changes: 3 additions & 6 deletions src/rx-schema.ts
Expand Up @@ -25,15 +25,13 @@ import {
} from './types';

export class RxSchema<T = any> {
public compoundIndexes: string[] | string[][];
public indexes: string[][];
public primaryPath: keyof T;
public finalFields: string[];

constructor(
public readonly jsonID: RxJsonSchema<T>
) {
this.compoundIndexes = this.jsonID.compoundIndexes as any;
this.indexes = getIndexes(this.jsonID);

// primary is always required
Expand Down Expand Up @@ -239,7 +237,7 @@ export function hasCrypt(jsonSchema: RxJsonSchema): boolean {
export function getIndexes<T = any>(
jsonID: RxJsonSchema<T>
): string[][] {
return (jsonID.indexes || []).map(indexPath => [indexPath]).concat(jsonID.compoundIndexes || []);
return (jsonID.indexes || []).map(index => Array.isArray(index) ? index : [index]);
}

/**
Expand Down Expand Up @@ -280,7 +278,6 @@ export function getFinalFields<T = any>(
return ret;
}


/**
* orders the schemas attributes by alphabetical order
* @return jsonSchema - ordered
Expand All @@ -307,8 +304,8 @@ const fillWithDefaultSettings = function (
if (!schemaObj.hasOwnProperty('keyCompression'))
schemaObj.keyCompression = false;

// compoundIndexes must be array
schemaObj.compoundIndexes = schemaObj.compoundIndexes || [];
// indexes must be array
schemaObj.indexes = schemaObj.indexes || [];

// required must be array
schemaObj.required = schemaObj.required || [];
Expand Down
5 changes: 2 additions & 3 deletions src/types/rx-error.ts
Expand Up @@ -83,9 +83,8 @@ export interface RxErrorParameters {
readonly parallel?: boolean;
readonly collection?: any;
readonly database?: any;
readonly compoundIndexes?: string[] | string[][] | undefined;
readonly indexes?: string[] | undefined;
readonly indexPath?: string;
readonly indexes?: Array<string|string[]>;
readonly index?: string|string[];
}

/**
Expand Down
3 changes: 1 addition & 2 deletions src/types/rx-schema.ts
Expand Up @@ -68,8 +68,7 @@ export declare class RxJsonSchema<T = any> {
type: 'object' | string;
properties: { [key in keyof T]: TopLevelProperty | PrimaryProperty };
required?: (keyof T)[];
indexes?: string[];
compoundIndexes?: string[][];
indexes?: Array<string|string[]>;
keyCompression?: boolean;
/**
* if not set, rxdb will set 'false' as default
Expand Down
29 changes: 21 additions & 8 deletions test/helper/schemas.ts
Expand Up @@ -491,6 +491,22 @@ export const encryptedDeepHuman: RxJsonSchema = {
required: ['firstName', 'secret']
};

export const notExistingIndex: RxJsonSchema = {
title: 'index',
version: 0,
description: 'this schema has a specified index which does not exists',
type: 'object',
keyCompression: true,
properties: {
address: {
type: 'object',
properties: {
street: { type: 'string' }
}
}
},
indexes: ['address.apartment']
};

export const compoundIndex: RxJsonSchema = {
title: 'compund index',
Expand All @@ -509,12 +525,12 @@ export const compoundIndex: RxJsonSchema = {
type: 'integer'
}
},
compoundIndexes: [
indexes: [
['passportId', 'passportCountry']
]
};

export const compoundIndexNoString: RxJsonSchema = {
export const compoundIndexNoString: any = {
title: 'compund index',
version: 0,
description: 'this schema has a compoundIndex',
Expand All @@ -531,12 +547,11 @@ export const compoundIndexNoString: RxJsonSchema = {
type: 'integer'
}
},
compoundIndexes: [
['passportId', 'passportCountry']
indexes: [
[10, 'passportCountry']
]
};


export const wrongCompoundFormat: any = {
title: 'compund index',
version: 0,
Expand All @@ -554,9 +569,7 @@ export const wrongCompoundFormat: any = {
type: 'integer'
}
},
compoundIndexes: [{
foo: 'bar'
}]
indexes: [ { foo: 'bar' } ]
};


Expand Down
18 changes: 9 additions & 9 deletions test/unit/query-change-detector.test.ts
Expand Up @@ -567,29 +567,29 @@ config.parallel('query-change-detector.test.js', () => {
type: 'number'
},
read: {
description: 'true if was read by the reciever',
description: 'true if was read by the receiver',
type: 'boolean'
},
sender: {
type: 'string',
ref: 'users'
},
reciever: {
receiver: {
type: 'string',
ref: 'users'
}
},
indexes: ['time'],
compoundIndexes: [
indexes: [
'time',
['sender', 'time'],
['reciever', 'time']
['receiver', 'time']
],
required: [
'text',
'time',
'read',
'sender',
'reciever'
'receiver'
]
};
const col = await humansCollection.createBySchema(schema);
Expand All @@ -601,15 +601,15 @@ config.parallel('query-change-detector.test.js', () => {
sender: {
$eq: user1
},
reciever: {
receiver: {
$eq: user2
}
},
{
sender: {
$eq: user2
},
reciever: {
receiver: {
$eq: user1
}
}
Expand All @@ -626,7 +626,7 @@ config.parallel('query-change-detector.test.js', () => {
time: AsyncTestUtil.randomNumber(1, 1000),
read: false,
sender: '3',
reciever: '4'
receiver: '4'
});

await getQuery().exec();
Expand Down
3 changes: 3 additions & 0 deletions test/unit/rx-schema.test.ts
Expand Up @@ -137,6 +137,9 @@ config.parallel('rx-schema.test.js', () => {
it('break when index is no string', () => {
assert.throws(() => SchemaCheck.checkSchema(schemas.nostringIndex), Error);
});
it('break when index does not exist in schema properties', () => {
assert.throws(() => SchemaCheck.checkSchema(schemas.notExistingIndex), Error);
})
it('break compoundIndex key is no string', () => {
assert.throws(() => SchemaCheck.checkSchema(schemas.compoundIndexNoString), Error);
});
Expand Down

0 comments on commit 924f92f

Please sign in to comment.