azurite
Version:
An open source Azure Storage API compatible server
203 lines • 6.83 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const sequelize_1 = require("sequelize");
const AllExtentsAsyncIterator_1 = tslib_1.__importDefault(require("./AllExtentsAsyncIterator"));
// tslint:disable: max-classes-per-file
class ExtentsModel extends sequelize_1.Model {
}
/**
* A SQL based extent metadata storage implementation based on Sequelize.
* Refer to CONTRIBUTION.md for how to setup SQL database environment.
*
* @export
* @class SqlExtentMetadataStore
* @implements {IExtentMetadataStore}
*/
class SqlExtentMetadataStore {
/**
* Creates an instance of SqlExtentMetadataStore.
*
* @param {string} connectionURI For example, "postgres://user:pass@example.com:5432/dbname"
* @param {SequelizeOptions} [sequelizeOptions]
* @memberof SqlBlobMetadataStore
*/
constructor(connectionURI, sequelizeOptions) {
this.initialized = false;
this.closed = false;
// Enable encrypt connection for SQL Server
if (connectionURI.startsWith("mssql") && sequelizeOptions) {
sequelizeOptions.dialectOptions = sequelizeOptions.dialectOptions || {};
sequelizeOptions.dialectOptions.options =
sequelizeOptions.dialectOptions.options || {};
sequelizeOptions.dialectOptions.options.encrypt = true;
}
this.sequelize = new sequelize_1.Sequelize(connectionURI, sequelizeOptions);
}
async init() {
await this.sequelize.authenticate();
ExtentsModel.init({
id: {
type: "VARCHAR(255)",
primaryKey: true
},
locationId: {
allowNull: false,
type: "VARCHAR(255)"
},
path: {
type: "VARCHAR(255)"
},
size: {
allowNull: false,
type: sequelize_1.BIGINT.UNSIGNED
},
lastModifiedInMS: {
allowNull: false,
type: sequelize_1.BIGINT.UNSIGNED
}
}, { sequelize: this.sequelize, modelName: "Extents", timestamps: false });
// TODO: Remove this part which only for test.
await this.sequelize.sync();
this.initialized = true;
}
isInitialized() {
return this.initialized;
}
async close() {
await this.sequelize.close();
this.closed = true;
}
isClosed() {
return this.closed;
}
async clean() {
// TODO: Implement cleanup in database
}
/**
* Update the extent status in DB. A new item will be created if the extent does not exists.
*
* @param {IExtentModel} extent
* @returns {Promise<void>}
* @memberof LokiExtentMetadata
*/
async updateExtent(extent) {
return ExtentsModel.upsert({
...extent
})
.then(() => {
return;
})
.catch((err) => {
// console.log(`SqlExtentMetadataStore.updateExtent() upsert err:${err}`);
throw err;
});
}
/**
*
* List extents.
* @param {string} [id]
* @param {number} [maxResults]
* @param {(number | undefined)} [marker]
* @param {Date} [queryTime]
* @param {number} [protectTimeInMs]
* @returns {(Promise<[IExtentModel[], number | undefined]>)}
* @memberof SqlExtentMetadataStore
*/
async listExtents(id, maxResults, marker, queryTime, protectTimeInMs) {
const query = {};
if (id !== undefined) {
query.id = id;
// console.log(`SqlExtentMetadataStore.listExtents() query ${id}`);
}
if (maxResults === undefined) {
maxResults = 5000;
}
if (protectTimeInMs === undefined) {
protectTimeInMs = 0;
}
if (queryTime !== undefined) {
query.lastModifiedInMS = {
[sequelize_1.Op.lt]: queryTime.getTime() - protectTimeInMs
};
}
if (marker !== undefined) {
query.id = {
[sequelize_1.Op.gt]: marker
};
}
const modelConvert = (extentsModel) => {
const getId = this.getModelValue(extentsModel, "id", true);
return {
id: getId,
locationId: this.getModelValue(extentsModel, "locationId", true),
path: this.getModelValue(extentsModel, "path") || getId,
size: this.getModelValue(extentsModel, "size", true),
lastModifiedInMS: this.getModelValue(extentsModel, "lastModifiedInMS", true)
};
};
return ExtentsModel.findAll({
limit: maxResults,
where: query,
order: [["id", "ASC"]]
}).then((res) => {
if (res.length < maxResults) {
return [res.map((val) => modelConvert(val)), undefined];
}
else {
const tailItem = res[res.length - 1];
const nextMarker = this.getModelValue(tailItem, "id", true);
return [res.map((val) => modelConvert(val)), nextMarker];
}
});
}
/**
* Delete the extent metadata from DB with the extentId.
*
* @param {string} extentId
* @returns {Promise<void>}
* @memberof IExtentMetadata
*/
async deleteExtent(extentId) {
return ExtentsModel.destroy({
where: {
id: extentId
}
}).then(() => {
return;
});
}
/**
* Get the locationId for a given extentId.
*
* @param {string} extentId
* @returns {Promise<string>}
* @memberof IExtentMetadata
*/
async getExtentLocationId(extentId) {
return ExtentsModel.findOne({
where: {
id: extentId
}
}).then((res) => {
if (res === null || res === undefined) {
throw Error(`SqlExtentMetadataStore:getExtentLocationId() Error. Extent not exists.`);
}
const locationId = this.getModelValue(res, "locationId", true);
return locationId;
});
}
iteratorExtents() {
return new AllExtentsAsyncIterator_1.default(this);
}
getModelValue(model, key, isRequired) {
const value = model.get(key);
if (value === undefined && isRequired === true) {
// tslint:disable-next-line:max-line-length
throw new Error(`SqlBlobMetadataStore:getModelValue() error. ${key} is required but value from database model is undefined.`);
}
return value;
}
}
exports.default = SqlExtentMetadataStore;
//# sourceMappingURL=SqlExtentMetadataStore.js.map
;