chore: Fixes issue related to flow types (#4724)
* Fixes issue related to flow types * Improves type inference on where clause, index * run parse-server start on liveQueryServer only on mongo, state leaks on postgres
This commit is contained in:
@@ -102,46 +102,47 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
parseLiveQueryServer.server.close(done);
|
parseLiveQueryServer.server.close(done);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can be initialized through ParseServer without liveQueryServerOptions', function(done) {
|
describe_only_db('mongo')('initialization', () => {
|
||||||
const parseServer = ParseServer.start({
|
it('can be initialized through ParseServer without liveQueryServerOptions', function(done) {
|
||||||
appId: 'hello',
|
const parseServer = ParseServer.start({
|
||||||
masterKey: 'world',
|
appId: 'hello',
|
||||||
port: 22345,
|
masterKey: 'world',
|
||||||
mountPath: '/1',
|
port: 22345,
|
||||||
serverURL: 'http://localhost:12345/1',
|
mountPath: '/1',
|
||||||
liveQuery: {
|
serverURL: 'http://localhost:12345/1',
|
||||||
classNames: ['Yolo']
|
liveQuery: {
|
||||||
},
|
classNames: ['Yolo']
|
||||||
startLiveQueryServer: true
|
},
|
||||||
|
startLiveQueryServer: true
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(parseServer.liveQueryServer).not.toBeUndefined();
|
||||||
|
expect(parseServer.liveQueryServer.server).toBe(parseServer.server);
|
||||||
|
parseServer.server.close(() => done());
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(parseServer.liveQueryServer).not.toBeUndefined();
|
it('can be initialized through ParseServer with liveQueryServerOptions', function(done) {
|
||||||
expect(parseServer.liveQueryServer.server).toBe(parseServer.server);
|
const parseServer = ParseServer.start({
|
||||||
parseServer.server.close(() => done());
|
appId: 'hello',
|
||||||
});
|
masterKey: 'world',
|
||||||
|
port: 22346,
|
||||||
|
mountPath: '/1',
|
||||||
|
serverURL: 'http://localhost:12345/1',
|
||||||
|
liveQuery: {
|
||||||
|
classNames: ['Yolo']
|
||||||
|
},
|
||||||
|
liveQueryServerOptions: {
|
||||||
|
port: 22347,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
it('can be initialized through ParseServer with liveQueryServerOptions', function(done) {
|
expect(parseServer.liveQueryServer).not.toBeUndefined();
|
||||||
const parseServer = ParseServer.start({
|
expect(parseServer.liveQueryServer.server).not.toBe(parseServer.server);
|
||||||
appId: 'hello',
|
parseServer.liveQueryServer.server.close();
|
||||||
masterKey: 'world',
|
parseServer.server.close(() => done());
|
||||||
port: 22346,
|
|
||||||
mountPath: '/1',
|
|
||||||
serverURL: 'http://localhost:12345/1',
|
|
||||||
liveQuery: {
|
|
||||||
classNames: ['Yolo']
|
|
||||||
},
|
|
||||||
liveQueryServerOptions: {
|
|
||||||
port: 22347,
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(parseServer.liveQueryServer).not.toBeUndefined();
|
|
||||||
expect(parseServer.liveQueryServer.server).not.toBe(parseServer.server);
|
|
||||||
parseServer.liveQueryServer.server.close();
|
|
||||||
parseServer.server.close(() => done());
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('can handle connect command', function() {
|
it('can handle connect command', function() {
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer(10, 10, {});
|
const parseLiveQueryServer = new ParseLiveQueryServer(10, 10, {});
|
||||||
const parseWebSocket = {
|
const parseWebSocket = {
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ export class MongoStorageAdapter implements StorageAdapter {
|
|||||||
return this.connectionPromise;
|
return this.connectionPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
handleError<T>(error: ?Error): Promise<T> {
|
handleError<T>(error: ?(Error | Parse.Error)): Promise<T> {
|
||||||
if (error && error.code === 13) { // Unauthorized error
|
if (error && error.code === 13) { // Unauthorized error
|
||||||
delete this.client;
|
delete this.client;
|
||||||
delete this.database;
|
delete this.database;
|
||||||
|
|||||||
@@ -233,7 +233,13 @@ const joinTablesForSchema = (schema) => {
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
const buildWhereClause = ({ schema, query, index }) => {
|
interface WhereClause {
|
||||||
|
pattern: string;
|
||||||
|
values: Array<any>;
|
||||||
|
sorts: Array<any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const buildWhereClause = ({ schema, query, index }): WhereClause => {
|
||||||
const patterns = [];
|
const patterns = [];
|
||||||
let values = [];
|
let values = [];
|
||||||
const sorts = [];
|
const sorts = [];
|
||||||
@@ -611,6 +617,9 @@ const buildWhereClause = ({ schema, query, index }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class PostgresStorageAdapter implements StorageAdapter {
|
export class PostgresStorageAdapter implements StorageAdapter {
|
||||||
|
|
||||||
|
canSortOnJoinTables: boolean;
|
||||||
|
|
||||||
// Private
|
// Private
|
||||||
_collectionPrefix: string;
|
_collectionPrefix: string;
|
||||||
_client: any;
|
_client: any;
|
||||||
@@ -625,6 +634,7 @@ export class PostgresStorageAdapter implements StorageAdapter {
|
|||||||
const { client, pgp } = createClient(uri, databaseOptions);
|
const { client, pgp } = createClient(uri, databaseOptions);
|
||||||
this._client = client;
|
this._client = client;
|
||||||
this._pgp = pgp;
|
this._pgp = pgp;
|
||||||
|
this.canSortOnJoinTables = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
handleShutdown() {
|
handleShutdown() {
|
||||||
@@ -862,7 +872,7 @@ export class PostgresStorageAdapter implements StorageAdapter {
|
|||||||
return this._client.task('delete-all-classes', function * (t) {
|
return this._client.task('delete-all-classes', function * (t) {
|
||||||
try {
|
try {
|
||||||
const results = yield t.any('SELECT * FROM "_SCHEMA"');
|
const results = yield t.any('SELECT * FROM "_SCHEMA"');
|
||||||
const joins = results.reduce((list, schema) => {
|
const joins = results.reduce((list: Array<string>, schema: any) => {
|
||||||
return list.concat(joinTablesForSchema(schema.schema));
|
return list.concat(joinTablesForSchema(schema.schema));
|
||||||
}, []);
|
}, []);
|
||||||
const classes = ['_SCHEMA', '_PushStatus', '_JobStatus', '_JobSchedule', '_Hooks', '_GlobalConfig', '_Audience', ...results.map(result => result.className), ...joins];
|
const classes = ['_SCHEMA', '_PushStatus', '_JobStatus', '_JobSchedule', '_Hooks', '_GlobalConfig', '_Audience', ...results.map(result => result.className), ...joins];
|
||||||
@@ -895,7 +905,7 @@ export class PostgresStorageAdapter implements StorageAdapter {
|
|||||||
// Returns a Promise.
|
// Returns a Promise.
|
||||||
deleteFields(className: string, schema: SchemaType, fieldNames: string[]): Promise<void> {
|
deleteFields(className: string, schema: SchemaType, fieldNames: string[]): Promise<void> {
|
||||||
debug('deleteFields', className, fieldNames);
|
debug('deleteFields', className, fieldNames);
|
||||||
fieldNames = fieldNames.reduce((list, fieldName) => {
|
fieldNames = fieldNames.reduce((list: Array<string>, fieldName: string) => {
|
||||||
const field = schema.fields[fieldName]
|
const field = schema.fields[fieldName]
|
||||||
if (field.type !== 'Relation') {
|
if (field.type !== 'Relation') {
|
||||||
list.push(fieldName);
|
list.push(fieldName);
|
||||||
@@ -1149,14 +1159,14 @@ export class PostgresStorageAdapter implements StorageAdapter {
|
|||||||
} else if (fieldName == 'authData') {
|
} else if (fieldName == 'authData') {
|
||||||
// This recursively sets the json_object
|
// This recursively sets the json_object
|
||||||
// Only 1 level deep
|
// Only 1 level deep
|
||||||
const generate = (jsonb, key, value) => {
|
const generate = (jsonb: string, key: string, value: any) => {
|
||||||
return `json_object_set_key(COALESCE(${jsonb}, '{}'::jsonb), ${key}, ${value})::jsonb`;
|
return `json_object_set_key(COALESCE(${jsonb}, '{}'::jsonb), ${key}, ${value})::jsonb`;
|
||||||
}
|
}
|
||||||
const lastKey = `$${index}:name`;
|
const lastKey = `$${index}:name`;
|
||||||
const fieldNameIndex = index;
|
const fieldNameIndex = index;
|
||||||
index += 1;
|
index += 1;
|
||||||
values.push(fieldName);
|
values.push(fieldName);
|
||||||
const update = Object.keys(fieldValue).reduce((lastKey, key) => {
|
const update = Object.keys(fieldValue).reduce((lastKey: string, key: string) => {
|
||||||
const str = generate(lastKey, `$${index}::text`, `$${index + 1}::jsonb`)
|
const str = generate(lastKey, `$${index}::text`, `$${index + 1}::jsonb`)
|
||||||
index += 2;
|
index += 2;
|
||||||
let value = fieldValue[key];
|
let value = fieldValue[key];
|
||||||
@@ -1259,13 +1269,13 @@ export class PostgresStorageAdapter implements StorageAdapter {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const keysToDelete = Object.keys(originalUpdate).filter(k => {
|
const keysToDelete: Array<string> = Object.keys(originalUpdate).filter(k => {
|
||||||
// choose top level fields that have a delete operation set.
|
// choose top level fields that have a delete operation set.
|
||||||
const value = originalUpdate[k];
|
const value = originalUpdate[k];
|
||||||
return value && value.__op === 'Delete' && k.split('.').length === 2 && k.split(".")[0] === fieldName;
|
return value && value.__op === 'Delete' && k.split('.').length === 2 && k.split(".")[0] === fieldName;
|
||||||
}).map(k => k.split('.')[1]);
|
}).map(k => k.split('.')[1]);
|
||||||
|
|
||||||
const deletePatterns = keysToDelete.reduce((p, c, i) => {
|
const deletePatterns = keysToDelete.reduce((p: string, c: string, i: number) => {
|
||||||
return p + ` - '$${index + 1 + i}:value'`;
|
return p + ` - '$${index + 1 + i}:value'`;
|
||||||
}, '');
|
}, '');
|
||||||
|
|
||||||
@@ -1556,7 +1566,7 @@ export class PostgresStorageAdapter implements StorageAdapter {
|
|||||||
aggregate(className: string, schema: any, pipeline: any) {
|
aggregate(className: string, schema: any, pipeline: any) {
|
||||||
debug('aggregate', className, pipeline);
|
debug('aggregate', className, pipeline);
|
||||||
const values = [className];
|
const values = [className];
|
||||||
let index = 2;
|
let index: number = 2;
|
||||||
let columns: string[] = [];
|
let columns: string[] = [];
|
||||||
let countField = null;
|
let countField = null;
|
||||||
let groupValues = null;
|
let groupValues = null;
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ export type UpdateQueryOptions = {
|
|||||||
export type FullQueryOptions = QueryOptions & UpdateQueryOptions;
|
export type FullQueryOptions = QueryOptions & UpdateQueryOptions;
|
||||||
|
|
||||||
export interface StorageAdapter {
|
export interface StorageAdapter {
|
||||||
|
canSortOnJoinTables: boolean;
|
||||||
|
|
||||||
classExists(className: string): Promise<boolean>;
|
classExists(className: string): Promise<boolean>;
|
||||||
setClassLevelPermissions(className: string, clps: any): Promise<void>;
|
setClassLevelPermissions(className: string, clps: any): Promise<void>;
|
||||||
createClass(className: string, schema: SchemaType): Promise<void>;
|
createClass(className: string, schema: SchemaType): Promise<void>;
|
||||||
|
|||||||
Reference in New Issue
Block a user