diff --git a/backend/model/sql/SQLConnection.ts b/backend/model/sql/SQLConnection.ts index 578254a0..6d07e504 100644 --- a/backend/model/sql/SQLConnection.ts +++ b/backend/model/sql/SQLConnection.ts @@ -33,7 +33,7 @@ export class SQLConnection { SharingEntity ]; options.synchronize = true; - // options.logging = "all" ; + options.logging = "all"; this.connection = await createConnection(options); } return this.connection; @@ -54,7 +54,7 @@ export class SQLConnection { SharingEntity ]; options.synchronize = true; - options.logging = "all"; + //options.logging = "all"; const conn = await createConnection(options); await conn.close(); return true; @@ -98,6 +98,7 @@ export class SQLConnection { try { if (this.connection != null) { await this.connection.close(); + this.connection = null; } } catch (err) { console.error(err); diff --git a/backend/model/sql/enitites/DirectoryEntity.ts b/backend/model/sql/enitites/DirectoryEntity.ts index a136e638..60739daf 100644 --- a/backend/model/sql/enitites/DirectoryEntity.ts +++ b/backend/model/sql/enitites/DirectoryEntity.ts @@ -14,9 +14,15 @@ export class DirectoryEntity implements DirectoryDTO { @Column() path: string; + /** + * last time the directory was modified (from outside, eg.: a new photo was added) + */ @Column('bigint') public lastModified: number; + /** + * Last time the directory was fully scanned, not only for a few photos to create a preview + */ @Column({type: "bigint", nullable: true}) public lastScanned: number; diff --git a/package.json b/package.json index 605e9f79..285f0e92 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pigallery2", - "version": "1.0.0-rc.1", + "version": "1.0.0", "description": "This is a photo gallery optimised for running low resource servers (especially on raspberry pi)", "author": "Patrik J. Braun", "homepage": "https://github.com/bpatrik/PiGallery2", @@ -11,7 +11,7 @@ "install": "tsc && ng build -prod", "build-release": "gulp build-release", "pretest": "tsc", - "test": "ng test --single-run && mocha --recursive test/backend/unit", + "test": "ng test --single-run && mocha --recursive test/backend/unit && mocha --recursive test/backend/integration", "start": "node ./backend/index", "ng": "ng", "lint": "ng lint", @@ -37,7 +37,7 @@ "ts-exif-parser": "0.1.23", "ts-node-iptc": "1.0.9", "typeconfig": "1.0.5", - "typeorm": "0.1.1", + "typeorm": "0.1.9", "winston": "2.4.0" }, "devDependencies": { diff --git a/test/backend/integration/model/sql/typeorm.ts b/test/backend/integration/model/sql/typeorm.ts new file mode 100644 index 00000000..43753fa4 --- /dev/null +++ b/test/backend/integration/model/sql/typeorm.ts @@ -0,0 +1,212 @@ +import {expect} from "chai"; +import * as fs from "fs"; +import * as path from "path"; +import {Config} from "../../../../../common/config/private/Config"; +import {DatabaseType} from "../../../../../common/config/private/IPrivateConfig"; +import {SQLConnection} from "../../../../../backend/model/sql/SQLConnection"; +import {UserEntity} from "../../../../../backend/model/sql/enitites/UserEntity"; +import {UserRoles} from "../../../../../common/entities/UserDTO"; +import {PasswordHelper} from "../../../../../backend/model/PasswordHelper"; +import {DirectoryEntity} from "../../../../../backend/model/sql/enitites/DirectoryEntity"; +import { + CameraMetadataEntity, GPSMetadataEntity, ImageSizeEntity, PhotoEntity, PhotoMetadataEntity, + PositionMetaDataEntity +} from "../../../../../backend/model/sql/enitites/PhotoEntity"; + +describe('Typeorm integration', () => { + + + const tempDir = path.join(__dirname, "../../tmp"); + const dbPath = path.join(tempDir, "test.db"); + const setUpSqlDB = () => { + if (fs.existsSync(dbPath)) { + fs.unlinkSync(dbPath); + } + if (!fs.existsSync(tempDir)) { + fs.mkdirSync(tempDir); + } + + Config.Server.database.type = DatabaseType.sqlite; + Config.Server.database.sqlite.storage = dbPath; + + }; + + const teardownUpSqlDB = async () => { + await SQLConnection.close(); + if (fs.existsSync(dbPath)) { + fs.unlinkSync(dbPath); + } + if (fs.existsSync(tempDir)) { + fs.rmdirSync(tempDir); + } + }; + + beforeEach(() => { + setUpSqlDB(); + }); + + afterEach(async () => { + await teardownUpSqlDB(); + }); + + + const getDir = () => { + const d = new DirectoryEntity(); + d.name = "test dir"; + d.path = "."; + d.lastModified = Date.now(); + d.lastScanned = null; + d.parent = null; + d.photos = []; + d.directories = []; + return d; + }; + + + const getPhoto = () => { + const sd = new ImageSizeEntity(); + sd.height = 200; + sd.width = 200; + const gps = new GPSMetadataEntity(); + gps.altitude = 1; + gps.latitude = 1; + gps.longitude = 1; + const pd = new PositionMetaDataEntity(); + pd.city = "New York"; + pd.country = "Alderan"; + pd.state = "Death star"; + pd.GPSData = gps; + const cd = new CameraMetadataEntity(); + cd.ISO = 100; + cd.model = "60D"; + cd.maker = "Canon"; + cd.fStop = 1; + cd.exposure = 1; + cd.focalLength = 1; + cd.lens = "Lens"; + const m = new PhotoMetadataEntity(); + m.keywords = ["apple"]; + m.cameraData = cd; + m.positionData = pd; + m.size = sd; + m.creationDate = Date.now(); + m.fileSize = 123456789; + + + const d = new PhotoEntity(); + d.name = "test photo.jpg"; + d.directory = null; + d.metadata = m; + return d; + }; + + it('should open and close connection', async () => { + const conn = await SQLConnection.getConnection(); + expect(conn.isConnected).to.equal(true); + await SQLConnection.close(); + expect(conn.isConnected).to.equal(false); + }); + + it('should open and close connection twice', async () => { + let conn = await SQLConnection.getConnection(); + expect(conn.isConnected).to.equal(true); + await SQLConnection.close(); + expect(conn.isConnected).to.equal(false); + + conn = await SQLConnection.getConnection(); + expect(conn.isConnected).to.equal(true); + await SQLConnection.close(); + expect(conn.isConnected).to.equal(false); + }); + + it('should add a user', async () => { + const conn = await SQLConnection.getConnection(); + const userRepository = conn.getRepository(UserEntity); + const a = new UserEntity(); + a.name = "test"; + a.password = PasswordHelper.cryptPassword("test"); + a.role = UserRoles.Admin; + await userRepository.save(a); + expect((await userRepository.find()).length).to.equal(1); + }); + + + it('should add a dir', async () => { + const conn = await SQLConnection.getConnection(); + const dr = conn.getRepository(DirectoryEntity); + await dr.save(getDir()); + expect((await dr.find()).length).to.equal(1); + }); + + it('should add a photo', async () => { + const conn = await SQLConnection.getConnection(); + const pr = conn.getRepository(PhotoEntity); + const dir = await conn.getRepository(DirectoryEntity).save(getDir()); + let photo = getPhoto(); + photo.directory = dir; + await pr.save(photo); + expect((await pr.find()).length).to.equal(1); + }); + + it('should find a photo', async () => { + const conn = await SQLConnection.getConnection(); + const pr = conn.getRepository(PhotoEntity); + const dir = await conn.getRepository(DirectoryEntity).save(getDir()); + let photo = getPhoto(); + photo.directory = dir; + await pr.save(photo); + + let photos = await pr + .createQueryBuilder("photo") + .orderBy("photo.metadata.creationDate", "ASC") + .where('photo.metadata.positionData.city LIKE :text COLLATE utf8_general_ci', {text: "%" + photo.metadata.positionData.city + "%"}) + .innerJoinAndSelect("photo.directory", "directory") + .limit(10) + .getMany(); + + expect(photos.length).to.equal(1); + expect(photos[0].directory.name).to.equal(dir.name); + }); + + + it('should not find a photo', async () => { + const conn = await SQLConnection.getConnection(); + const pr = conn.getRepository(PhotoEntity); + const dir = await conn.getRepository(DirectoryEntity).save(getDir()); + let photo = getPhoto(); + photo.directory = dir; + const city = photo.metadata.positionData.city; + photo.metadata.positionData = null; + await pr.save(photo); + let photos = await pr + .createQueryBuilder("photo") + .orderBy("photo.metadata.creationDate", "ASC") + .where('photo.metadata.positionData.city LIKE :text COLLATE utf8_general_ci', {text: "%" + city + "%"}) + .innerJoinAndSelect("photo.directory", "directory") + .limit(10) + .getMany(); + + expect(photos.length).to.equal(0); + }); + + it('should open and close connection twice with photo added ', async () => { + console.log("start-------------------------------------"); + let conn = await SQLConnection.getConnection(); + console.log("opnenn-------------------------------------"); + const dir = await conn.getRepository(DirectoryEntity).save(getDir()); + let dir2 = getDir(); + dir2.parent = dir; + await conn.getRepository(DirectoryEntity).save(dir2); + let photo = getPhoto(); + photo.directory = dir2; + await await conn.getRepository(PhotoEntity).save(photo); + await SQLConnection.close(); + expect(conn.isConnected).to.equal(false); + + conn = await SQLConnection.getConnection(); + expect(conn.isConnected).to.equal(true); + await SQLConnection.close(); + expect(conn.isConnected).to.equal(false); + }); + +});