diff --git a/libraries/supabase-js/package.json b/libraries/supabase-js/package.json index aa027d4e57..261043ad5b 100644 --- a/libraries/supabase-js/package.json +++ b/libraries/supabase-js/package.json @@ -40,9 +40,9 @@ "babel-plugin-add-module-exports": "^1.0.0", "babel-polyfill": "^6.26.0", "babel-preset-env": "^1.6.1", - "babel-preset-minify": "^0.5.0", + "babel-preset-minify": "^0.3.0", "chai": "^4.1.2", - "cross-env": "^5.1.3", + "cross-env": "^5.2.1", "mocha": "^6.1.3", "nyc": "^13.3.0", "rimraf": "^2.6.2" diff --git a/libraries/supabase-js/src/BaseChannel.js b/libraries/supabase-js/src/BaseChannel.js index 40e55f48f5..f2862a4004 100644 --- a/libraries/supabase-js/src/BaseChannel.js +++ b/libraries/supabase-js/src/BaseChannel.js @@ -1,10 +1,10 @@ import { Socket } from 'phoenix-channels' export default class BaseChannel { - constructor(tableName, apiSocket){ + constructor(tableName, apiSocket, uuid){ this.socket = new Socket(apiSocket) + this.uuid = uuid this.channel = this.socket.channel(tableName) - this.listeners = {} this.start() @@ -17,23 +17,7 @@ export default class BaseChannel { } on(eventName, callbackFunction){ - let ref = this.channel.on(eventName, callbackFunction) - this.listeners[ref] = eventName - return ref - } - - off(eventName, ref = null){ - // if ref is null, we just want to remove everything that has the eventName - if(typeof ref === 'null'){ - for (var ref in this.listeners){ - let eventNameValue = this.listeners[ref] - if(eventName === eventNameValue){ - this.off(eventName, ref) - } - } - } - - this.channel.off(eventName, ref) + this.channel.on(eventName, callbackFunction) } start(){ diff --git a/libraries/supabase-js/src/BaseRequest.js b/libraries/supabase-js/src/BaseRequest.js index 4ef6860aa2..3988f0f32f 100644 --- a/libraries/supabase-js/src/BaseRequest.js +++ b/libraries/supabase-js/src/BaseRequest.js @@ -34,7 +34,7 @@ class BaseRequest extends Request { * * @param {string|object} The user, bearer token, or user/pass object. * @param {string|void} The pass or undefined. - * @returns {ApiRequest} The API request object. + * @returns {BaseRequest} The API request object. */ auth (user, pass) { @@ -56,7 +56,7 @@ class BaseRequest extends Request { * All values are prefixed with `eq.`. * * @param {object} The object to match against. - * @returns {ApiRequest} The API request object. + * @returns {BaseRequest} The API request object. */ match (query) { @@ -70,7 +70,7 @@ class BaseRequest extends Request { * set as a query string value. Also always forces a root @id column. * * @param {string} The unformatted select string. - * @returns {ApiRequest} The API request object. + * @returns {BaseRequest} The API request object. */ select (select) { @@ -87,7 +87,7 @@ class BaseRequest extends Request { * @param {string} The property name to order by. * @param {bool} True for descending results, false by default. * @param {bool} True for nulls first, false by default. - * @returns {ApiRequest} The API request object. + * @returns {BaseRequest} The API request object. */ order (property, ascending = false, nullsFirst = false) { @@ -101,7 +101,7 @@ class BaseRequest extends Request { * * @param {number} The first object to select. * @param {number|void} The last object to select. - * @returns {ApiRequest} The API request object. + * @returns {BaseRequest} The API request object. */ range (from, to) { @@ -114,7 +114,7 @@ class BaseRequest extends Request { * Sets the header which signifies to PostgREST the response must be a single * object or 404. * - * @returns {ApiRequest} The API request object. + * @returns {BaseRequest} The API request object. */ single () { @@ -135,20 +135,22 @@ class BaseRequest extends Request { return reject(error) } - const { body, headers } = response + const { body, headers, status, statusCode, statusText } = response const contentRange = headers['content-range'] if (Array.isArray(body) && contentRange && contentRangeStructure.test(contentRange)) { body.fullLength = parseInt(contentRangeStructure.exec(contentRange)[3], 10) } - return resolve(body) + const returnBody = { body, status, statusCode, statusText} + + return resolve(returnBody) }) ) } /** - * Makes the ApiRequest object then-able. Allows for usage with + * Makes the BaseRequest object then-able. Allows for usage with * `Promise.resolve` and async/await contexts. Just a proxy for `.then()` on * the promise returned from `.end()`. * @@ -178,13 +180,13 @@ class BaseRequest extends Request { * * @param {string} The name of the column. * @param {any} The value of the column to be filtered. - * @returns {ApiRequest} The API request object. + * @returns {BaseRequest} The API request object. */ const filters = ['eq', 'gt', 'lt', 'gte', 'lte', 'like', 'ilike', 'is', 'in', 'not'] filters.forEach(filter => - ApiRequest.prototype[filter] = function filterValue (name, value) { + BaseRequest.prototype[filter] = function filterValue (name, value) { return this.query(`${name}=${filter}.${Array.isArray(value) ? value.join(',') : value}`) } ) diff --git a/libraries/supabase-js/src/index.js b/libraries/supabase-js/src/index.js index f6c877dcd8..82c896488b 100644 --- a/libraries/supabase-js/src/index.js +++ b/libraries/supabase-js/src/index.js @@ -1,20 +1,32 @@ import BaseRequest from './BaseRequest' +import BaseChannel from './BaseChannel' +import { uuid } from './utils/Helpers' class SupabaseClient { - constructor(supbaseUrl, supabaseKey, options) { + constructor(supabaseUrl, supabaseKey, options) { this.supabaseUrl = supabaseUrl this.supabaseKey = supabaseKey - + // this will be the case for now this.restUrl = supabaseUrl this.apiSocket = '' + + this.subscriptions = {} } /** * @todo */ - subscribe (tableName) { - return new BaseChannel(tableName, this.apiSocket) + subscribe(tableName) { + let uuid = uuid() + + this.subscriptions[uuid] = new BaseChannel(tableName, this.apiSocket, uuid) + return this.subscriptions[uuid] + } + + unsubscribe(subscription){ + subscription.stop() + delete this.subscriptions[subscription.uuid] } /** @@ -26,9 +38,10 @@ class SupabaseClient { * @returns {BaseRequest} The API request object. */ - request (method, path) { + request(method, path) { return new BaseRequest(method, this.restUrl + path) } + } /** @@ -38,23 +51,23 @@ class SupabaseClient { * @returns {BaseRequest} The API request object. */ -const methods = ['POST', 'GET', 'PATCH', 'PUT', 'DELETE'] +const methods = ['POST', 'GET', 'PATCH', 'DELETE'] -methods.forEach(method => - SupabaseClient.prototype[method.toLowerCase()] = tableName => { - path = `/${tableName}` +methods.forEach(method => { + SupabaseClient.prototype[method.toLowerCase()] = function requestMethod(tableName) { + let path = `/${tableName}` return this.request(method, path) } -) +}) const createClient = (supabaseUrl, supabaseKey, options = {}) => { - return new SupabaseClient(supabseUrl, supabaseKey, options) + return new SupabaseClient(supabaseUrl, supabaseKey, options) } export { createClient } /** - * TO BE REMOVED SOON + * TO BE REMOVED SOON */ // const defaultAwesomeFunction = (name) => { diff --git a/libraries/supabase-js/src/utils/Helpers.js b/libraries/supabase-js/src/utils/Helpers.js new file mode 100644 index 0000000000..7bb4b96973 --- /dev/null +++ b/libraries/supabase-js/src/utils/Helpers.js @@ -0,0 +1,8 @@ +export function uuid() { + function s4() { + return Math.floor((1 + Math.random()) * 0x10000) + .toString(16) + .substring(1) + } + return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4() +}