From 7e3220b6e182efc13b0f2673d1c60e1a4f105e3c Mon Sep 17 00:00:00 2001 From: gilzoide Date: Sat, 28 Jun 2025 12:36:24 -0300 Subject: [PATCH 01/11] Add SQLiteAsset asset script --- Editor.meta | 8 + Editor/Icons.meta | 8 + Editor/Icons/d_solar_database-bold.png | Bin 0 -> 399 bytes Editor/Icons/d_solar_database-bold.png.meta | 192 ++++++++++++++++++ Editor/Icons/d_solar_database-bold@2x.png | Bin 0 -> 621 bytes .../Icons/d_solar_database-bold@2x.png.meta | 192 ++++++++++++++++++ Editor/Icons/solar_database-bold.png | Bin 0 -> 401 bytes Editor/Icons/solar_database-bold.png.meta | 192 ++++++++++++++++++ Editor/Icons/solar_database-bold@2x.png | Bin 0 -> 679 bytes Editor/Icons/solar_database-bold@2x.png.meta | 192 ++++++++++++++++++ README.md | 2 + Runtime/SQLiteAsset.cs | 105 ++++++++++ Runtime/SQLiteAsset.cs.meta | 11 + 13 files changed, 902 insertions(+) create mode 100644 Editor.meta create mode 100644 Editor/Icons.meta create mode 100644 Editor/Icons/d_solar_database-bold.png create mode 100644 Editor/Icons/d_solar_database-bold.png.meta create mode 100644 Editor/Icons/d_solar_database-bold@2x.png create mode 100644 Editor/Icons/d_solar_database-bold@2x.png.meta create mode 100644 Editor/Icons/solar_database-bold.png create mode 100644 Editor/Icons/solar_database-bold.png.meta create mode 100644 Editor/Icons/solar_database-bold@2x.png create mode 100644 Editor/Icons/solar_database-bold@2x.png.meta create mode 100644 Runtime/SQLiteAsset.cs create mode 100644 Runtime/SQLiteAsset.cs.meta diff --git a/Editor.meta b/Editor.meta new file mode 100644 index 0000000..2059c29 --- /dev/null +++ b/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2247b5abd5a1c47bd9c80355cc56c5ef +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Icons.meta b/Editor/Icons.meta new file mode 100644 index 0000000..3e9bf56 --- /dev/null +++ b/Editor/Icons.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 196a203c3f399425bbfae08500a87e46 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Icons/d_solar_database-bold.png b/Editor/Icons/d_solar_database-bold.png new file mode 100644 index 0000000000000000000000000000000000000000..7cce7a93b73bf7efcca9cca3fe4c40b270a006bd GIT binary patch literal 399 zcmV;A0dW3_P)0q~ntsqJVNhL`M=^#W%T%m)w1R^-{$(snQ1d<2|#ggUm zeBR7^vKgDX_|TE2sVIu#*D#Flwr#~ViSxXws-xpLk>`2&Q-CB%mUUgPQ6Qc)l!)zo z-`|V?;y4ZwJg_NabM65oBU|g87?B)uLcP>9P0>&QmSwrRt}lT8k8Ad*5SnZ#2evx` z0QVp4D+MI|*|z-BmH<530U3}?UJ zf3dD20i(cp3-OIfBcN|63yJgu5I>(Z14;TKU6(C_?UFPD;ard^fx%!9V#6zjrAkT$ zIFqujPNx%+Dgj2f+YOMxE{1cuA4|)!T-Fsuku4LDCLzl29j`D?n$2dzjb{RHo-u9F zbtI5mAm$+qCz(DE^D*X=OJPgO$}pI1glY(|ahBEb?`E!&%T5SSMZI26&pRP^&FywO z&GrT|TT%i!V8BNm`!LAy<0MMhtK2gg__VNxJLU++J-Pvl6aXTukRLuyPAY+6{-*3C zPA3B6HkE)9fpcWxX=R2lzfoBfRY5}f@ky!#dc7W3!5eAl1AyQ*%%w=G1acBp`v44o zG@DJA%lXj<=+OtN5IDzQ^#Scb&U}+90eBXWW+0gZ>AGx@%MT=GqzSC6C~>a_Ez4;B zGj`}coE*7!KTy7yAi;bLpXhcY68!&%n1_`wCNk*0nmzCX)9GC;xOuyr00000NkvXX Hu0mjfc+vho literal 0 HcmV?d00001 diff --git a/Editor/Icons/d_solar_database-bold@2x.png.meta b/Editor/Icons/d_solar_database-bold@2x.png.meta new file mode 100644 index 0000000..67c73f8 --- /dev/null +++ b/Editor/Icons/d_solar_database-bold@2x.png.meta @@ -0,0 +1,192 @@ +fileFormatVersion: 2 +guid: 319f3bdfbe91a4af8aac8c8710acc4dc +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: iPhone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: VisionOS + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: tvOS + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Icons/solar_database-bold.png b/Editor/Icons/solar_database-bold.png new file mode 100644 index 0000000000000000000000000000000000000000..26b015bf50e444b2f371dd7ff69cf18ef0e72c2d GIT binary patch literal 401 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9GG!XV7ZFl&wkP>``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eBIWWC=+wzQKhjY!}W1p0=896yCmt5rAY@C1Jrc5$A^N!Dt zefqh#zga%luf2cTTktvSwA#?n-6p=>kqrtQcDvX8cGI}IMm=0btoKMOh}L}zIwb>3OBftkVY*22aNtLsy)?7wK> zx^=POixyR>ggK=^{J7SH!FE^b_UdA(n5@#AmkOsh-6@Ubo5eSK|0&j4`zNXVyxe*6 tc*{;(hRPo`dzSeZu<8bVHe9>S*j#SGjnykOegH#|!PC{xWt~$(6977CpaB2? literal 0 HcmV?d00001 diff --git a/Editor/Icons/solar_database-bold.png.meta b/Editor/Icons/solar_database-bold.png.meta new file mode 100644 index 0000000..6b80e92 --- /dev/null +++ b/Editor/Icons/solar_database-bold.png.meta @@ -0,0 +1,192 @@ +fileFormatVersion: 2 +guid: d05789d285ed2446a97f5c3f99ef13b6 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: iPhone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: VisionOS + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: tvOS + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Icons/solar_database-bold@2x.png b/Editor/Icons/solar_database-bold@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..ae25b70bc2a6fff249fb697fefd143e2ba1b8f47 GIT binary patch literal 679 zcmV;Y0$BZtP)c+ z>Oc@4n;$(<`3PGB(j(pLo^yidCjmkC(jwkaBYa(jX)R z=`biE9LKQ=g@RbG*Vbya5Mx$ZF;Xn4j*=$6FdB7J)-Sv7spN=8GjuB-WLz@nR1d($PkvfBn?m@j? zZzJjshJp@Y=Gy)$jK^sNgfayE{4@KJUSM zv3{rwvZ~2it#$*)Uf9Pj+VKkQ*uwZPt_tl(fVCsMa}SPL6F%G7!LSvJ02VXbdl2C) zT!($!+9Fti6AN~Ne`74O*{obF7PD<7>#QRVne3` z0i_S66f1RLGMPLUi^W$I*&jMy2P9tMf9QaxdZ^U_EVwyV2aw5I)Xf?H2YibT42Q#$ z4xDr#5+;2eUMVht@LMo#bX1c%A(9Xx6uDtj3P25A>pn=LKFj$4av$R?po1Se_jLxb z4kp!V)yB<5Mt)O70m6o*cf>-r&v7CG+hB2l9*A8b!gz)@O?)&v;SE^jd49Zrui*dy N002ovPDHLkV1gDNAOQdX literal 0 HcmV?d00001 diff --git a/Editor/Icons/solar_database-bold@2x.png.meta b/Editor/Icons/solar_database-bold@2x.png.meta new file mode 100644 index 0000000..afac1c2 --- /dev/null +++ b/Editor/Icons/solar_database-bold@2x.png.meta @@ -0,0 +1,192 @@ +fileFormatVersion: 2 +guid: 4f3ac3350a5be4f00917e4fb7aa5a213 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: iPhone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: VisionOS + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: tvOS + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/README.md b/README.md index b438b11..b3f0e19 100644 --- a/README.md +++ b/README.md @@ -104,6 +104,8 @@ Third-party code: - SQLite-net: [MIT license](Runtime/sqlite-net/LICENSE.txt) - SQLite3 Multiple Ciphers: [MIT license](https://github.com/utelle/SQLite3MultipleCiphers/blob/main/LICENSE) +Database icons from [Solar Icons Set](https://www.figma.com/community/file/1166831539721848736/solar-icons-set), licensed under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/) + ## Modifications made to SQLite-net source code - The value of `LibraryPath` was changed from `sqlite3` to `__Internal` in WebGL/iOS/tvOS/visionOS builds and `gilzoide-sqlite-net` for other platforms. diff --git a/Runtime/SQLiteAsset.cs b/Runtime/SQLiteAsset.cs new file mode 100644 index 0000000..b852b79 --- /dev/null +++ b/Runtime/SQLiteAsset.cs @@ -0,0 +1,105 @@ +using System; +using SQLite; +using UnityEngine; + +namespace SQLite +{ + public class SQLiteAsset : ScriptableObject + { + [Tooltip("Flags controlling how the SQLite connection should be opened. 'ReadWrite' and 'Create' flags will be ignored, since SQLite assets are read-only.")] + [SerializeField] private SQLiteOpenFlags _openFlags = SQLiteOpenFlags.ReadOnly; + + [Tooltip("Whether to store DateTime properties as ticks (true) or strings (false).")] + [SerializeField] private bool _storeDateTimeAsTicks = true; + + [Tooltip("Name of the file created for the database inside Streaming Assets folder during builds.\n\n" + + "If empty, the database bytes will be stored in the asset itself.\n\n" + + "Loading databases from Streaming Assets is not supported in Android and WebGL platforms.")] + [SerializeField] private string _streamingAssetsPath; + + [SerializeField, HideInInspector] private byte[] _bytes; + + /// + /// Flags controlling how the SQLite connection should be opened. + /// + /// + /// 'ReadWrite' and 'Create' flags will be ignored, since SQLite assets are read-only. + /// + public SQLiteOpenFlags OpenFlags + { + get => _openFlags; + set => _openFlags = value & ~(SQLiteOpenFlags.ReadWrite | SQLiteOpenFlags.Create); + } + + /// + /// Whether to store DateTime properties as ticks (true) or strings (false). + /// + /// + public bool StoreDateTimeAsTicks + { + get => _storeDateTimeAsTicks; + set => _storeDateTimeAsTicks = value; + } + + /// + /// Bytes that compose the SQLite database file. + /// + public byte[] Bytes + { + get => _bytes; + set => _bytes = value; + } + + /// + /// If true, the database bytes will be read from a file located at the Streaming Assets folder instead of storing all bytes in memory. + /// + public string StreamingAssetsPath + { + get => _streamingAssetsPath; + set => _streamingAssetsPath = value; + } + + /// + /// If true, the database bytes will be read from a file located at the Streaming Assets folder instead of storing all bytes in memory. + /// + public bool UseStreamingAssets => !string.IsNullOrWhiteSpace(_streamingAssetsPath); + + /// + /// Creates a new connection to the read-only SQLite database represented by this asset. + /// + /// + /// If is null. + public SQLiteConnection CreateConnection() + { +#if !UNITY_EDITOR && !UNITY_ANDROID && !UNITY_WEBGL + if (UseStreamingAssets) + { + string path = System.IO.Path.Combine(Application.streamingAssetsPath, _streamingAssetsPath); + return new SQLiteConnection(path); + } +#endif + if (Bytes == null) + { + throw new NullReferenceException(nameof(Bytes)); + } + + return new SQLiteConnection("").Deserialize(Bytes, null, SQLite3.DeserializeFlags.ReadOnly); + } + +#if UNITY_EDITOR + protected void OnValidate() + { + if (_openFlags.HasFlag(SQLiteOpenFlags.ReadWrite)) + { + Debug.LogWarning($"{nameof(SQLiteAsset)} does not support writing to the database. Ignoring \"ReadWrite\" flag.", this); + _openFlags &= ~SQLiteOpenFlags.ReadWrite; + } + if (_openFlags.HasFlag(SQLiteOpenFlags.Create)) + { + Debug.LogWarning($"{nameof(SQLiteAsset)} does not support creating database. Ignoring \"Create\" flag.", this); + _openFlags &= ~SQLiteOpenFlags.Create; + } + } +#endif + } +} diff --git a/Runtime/SQLiteAsset.cs.meta b/Runtime/SQLiteAsset.cs.meta new file mode 100644 index 0000000..c3762b2 --- /dev/null +++ b/Runtime/SQLiteAsset.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f2f61d07f5f634a01b7d297f944a71ef +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: d05789d285ed2446a97f5c3f99ef13b6, type: 3} + userData: + assetBundleName: + assetBundleVariant: From ab319dbb1e0cc07931debb5c4170625cbbec0694 Mon Sep 17 00:00:00 2001 From: gilzoide Date: Sat, 28 Jun 2025 12:36:52 -0300 Subject: [PATCH 02/11] Add SQLiteConnection.SerializeToAsset extension method --- Runtime/SQLiteConnectionExtensions.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Runtime/SQLiteConnectionExtensions.cs b/Runtime/SQLiteConnectionExtensions.cs index e0b68b6..1a1f81a 100644 --- a/Runtime/SQLiteConnectionExtensions.cs +++ b/Runtime/SQLiteConnectionExtensions.cs @@ -25,6 +25,7 @@ using Unity.Collections; using Unity.Collections.LowLevel.Unsafe; #endif +using UnityEngine; namespace SQLite { @@ -49,6 +50,16 @@ public static byte[] Serialize(this SQLiteConnection db, string schema = null) } } + public static SQLiteAsset SerializeToAsset(this SQLiteConnection db, string schema = null, SQLiteOpenFlags openFlags = SQLiteOpenFlags.ReadOnly, bool storeDateTimeAsTicks = true, string streamingAssetsPath = null) + { + SQLiteAsset asset = ScriptableObject.CreateInstance(); + asset.Bytes = db.Serialize(schema); + asset.OpenFlags = openFlags; + asset.StoreDateTimeAsTicks = storeDateTimeAsTicks; + asset.StreamingAssetsPath = streamingAssetsPath; + return asset; + } + public static SQLiteConnection Deserialize(this SQLiteConnection db, byte[] buffer, string schema = null, SQLite3.DeserializeFlags flags = SQLite3.DeserializeFlags.None) { return Deserialize(db, buffer, buffer.LongLength, schema, flags); From 095defdfd4b6e16fea379fd8a256a472d64bdecd Mon Sep 17 00:00:00 2001 From: gilzoide Date: Sat, 28 Jun 2025 12:47:21 -0300 Subject: [PATCH 03/11] Add SQLite asset custom editor, scripted importer and build processor --- Editor/Gilzoide.SqliteNet.Editor.asmdef | 16 +++++ Editor/Gilzoide.SqliteNet.Editor.asmdef.meta | 7 ++ Editor/SQLiteAssetBuildProcessor.cs | 69 +++++++++++++++++++ Editor/SQLiteAssetBuildProcessor.cs.meta | 11 +++ Editor/SQLiteAssetEditor.cs | 72 ++++++++++++++++++++ Editor/SQLiteAssetEditor.cs.meta | 11 +++ Editor/SQLiteAssetImporter.cs | 36 ++++++++++ Editor/SQLiteAssetImporter.cs.meta | 11 +++ README.md | 8 ++- 9 files changed, 240 insertions(+), 1 deletion(-) create mode 100644 Editor/Gilzoide.SqliteNet.Editor.asmdef create mode 100644 Editor/Gilzoide.SqliteNet.Editor.asmdef.meta create mode 100644 Editor/SQLiteAssetBuildProcessor.cs create mode 100644 Editor/SQLiteAssetBuildProcessor.cs.meta create mode 100644 Editor/SQLiteAssetEditor.cs create mode 100644 Editor/SQLiteAssetEditor.cs.meta create mode 100644 Editor/SQLiteAssetImporter.cs create mode 100644 Editor/SQLiteAssetImporter.cs.meta diff --git a/Editor/Gilzoide.SqliteNet.Editor.asmdef b/Editor/Gilzoide.SqliteNet.Editor.asmdef new file mode 100644 index 0000000..c2056c7 --- /dev/null +++ b/Editor/Gilzoide.SqliteNet.Editor.asmdef @@ -0,0 +1,16 @@ +{ + "name": "Gilzoide.SqliteNet.Editor", + "rootNamespace": "SQLite.Editor", + "references": [ + "GUID:17f96cd3b93974f6493e51a2f25c1241" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": false, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Editor/Gilzoide.SqliteNet.Editor.asmdef.meta b/Editor/Gilzoide.SqliteNet.Editor.asmdef.meta new file mode 100644 index 0000000..6728a4b --- /dev/null +++ b/Editor/Gilzoide.SqliteNet.Editor.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: bf1b03bab81fb4dbf9f325bfe2f10d29 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/SQLiteAssetBuildProcessor.cs b/Editor/SQLiteAssetBuildProcessor.cs new file mode 100644 index 0000000..a659975 --- /dev/null +++ b/Editor/SQLiteAssetBuildProcessor.cs @@ -0,0 +1,69 @@ +#if !UNITY_ANDROID && !UNITY_WEBGL +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using UnityEditor; +using UnityEditor.Build; +using UnityEditor.Build.Reporting; + +namespace SQLite.Editor +{ + public class SQLiteAssetBuildProcessor : IPreprocessBuildWithReport, IPostprocessBuildWithReport + { + public int callbackOrder => 0; + + public void OnPreprocessBuild(BuildReport report) + { + foreach (SQLiteAsset sqliteAsset in GetAffectedAssets()) + { + string filePath = $"Assets/StreamingAssets/{sqliteAsset.StreamingAssetsPath}"; + string directoryPath = Path.GetDirectoryName(filePath); + if (!Directory.Exists(directoryPath)) + { + Directory.CreateDirectory(directoryPath); + } + File.WriteAllBytes(filePath, sqliteAsset.Bytes); + sqliteAsset.Bytes = Array.Empty(); + } + } + + public void OnPostprocessBuild(BuildReport report) + { + foreach (SQLiteAsset sqliteAsset in GetAffectedAssets()) + { + string filePath = $"Assets/StreamingAssets/{sqliteAsset.StreamingAssetsPath}"; + if (File.Exists(filePath)) + { + sqliteAsset.Bytes = File.ReadAllBytes(filePath); + FileUtil.DeleteFileOrDirectory(filePath); + FileUtil.DeleteFileOrDirectory(filePath + ".meta"); + DeleteEmptyDirectories(Path.GetDirectoryName(filePath)); + } + } + } + + private static void DeleteEmptyDirectories(string directory) + { + while (!string.IsNullOrWhiteSpace(directory)) + { + if (Directory.EnumerateFileSystemEntries(directory).Any()) + { + return; + } + FileUtil.DeleteFileOrDirectory(directory); + FileUtil.DeleteFileOrDirectory(directory + ".meta"); + directory = Path.GetDirectoryName(directory); + } + } + + private static IEnumerable GetAffectedAssets() + { + return AssetDatabase.FindAssets($"t:{nameof(SQLiteAsset)}") + .Select(AssetDatabase.GUIDToAssetPath) + .Select(AssetDatabase.LoadAssetAtPath) + .Where(sqlite => sqlite.UseStreamingAssets); + } + } +} +#endif diff --git a/Editor/SQLiteAssetBuildProcessor.cs.meta b/Editor/SQLiteAssetBuildProcessor.cs.meta new file mode 100644 index 0000000..ec3c44f --- /dev/null +++ b/Editor/SQLiteAssetBuildProcessor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3c72b41ff6d7a4557bc93e8c99a1ce09 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/SQLiteAssetEditor.cs b/Editor/SQLiteAssetEditor.cs new file mode 100644 index 0000000..53159f7 --- /dev/null +++ b/Editor/SQLiteAssetEditor.cs @@ -0,0 +1,72 @@ +using System.Collections.Generic; +using UnityEditor; +using UnityEngine; + +namespace SQLite.Editor +{ + [CustomEditor(typeof(SQLiteAsset))] + [CanEditMultipleObjects] + public class SQLiteAssetEditor : UnityEditor.Editor + { + private class TableInfo + { + public string Name { get; set; } + public string Sql { get; set; } + + public void Deconstruct(out string name, out string sql) + { + name = Name; + sql = Sql; + } + } + + [SerializeField] private List _expandedTables = new List(); + + public override void OnInspectorGUI() + { + DrawDefaultInspector(); + EditorGUILayout.Space(); + + using (new EditorGUI.DisabledScope(true)) + { + EditorGUILayout.TextField("Database size in bytes", EditorUtility.FormatBytes(((SQLiteAsset) target).Bytes.Length)); + } + + if (serializedObject.isEditingMultipleObjects) + { + return; + } + + EditorGUILayout.Space(); + + using (new EditorGUI.DisabledScope(true)) + using (var db = ((SQLiteAsset) target).CreateConnection()) + { + EditorGUILayout.LabelField("Tables", EditorStyles.boldLabel); + EditorGUI.indentLevel++; + foreach ((string name, string sql) in db.Query("SELECT name, sql FROM SQLite_schema WHERE type = 'table'")) + { + bool previouslyExpanded = _expandedTables.Contains(name); + bool expanded = EditorGUILayout.Foldout(previouslyExpanded, name, true); + if (previouslyExpanded && !expanded) + { + _expandedTables.Remove(name); + } + else if (!previouslyExpanded && expanded) + { + _expandedTables.Add(name); + } + + if (expanded) + { + EditorGUILayout.TextField("SQL", sql); + int count = db.ExecuteScalar($"SELECT COUNT(*) FROM {SQLiteConnection.Quote(name)}"); + EditorGUILayout.IntField("Row Count", count); + } + EditorGUILayout.Space(); + } + EditorGUI.indentLevel--; + } + } + } +} diff --git a/Editor/SQLiteAssetEditor.cs.meta b/Editor/SQLiteAssetEditor.cs.meta new file mode 100644 index 0000000..1d64d2e --- /dev/null +++ b/Editor/SQLiteAssetEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4b01081d2adb9418391fe28f13086bcd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/SQLiteAssetImporter.cs b/Editor/SQLiteAssetImporter.cs new file mode 100644 index 0000000..b1d3a3b --- /dev/null +++ b/Editor/SQLiteAssetImporter.cs @@ -0,0 +1,36 @@ +using System.IO; +#if UNITY_2020_2_OR_NEWER +using UnityEditor.AssetImporters; +#else +using UnityEditor.Experimental.AssetImporters; +#endif +using UnityEngine; + +namespace SQLite.Editor +{ + [ScriptedImporter(0, new[] { "sqlite", "sqlite2", "sqlite3" })] + public class SQLiteAssetImporter : ScriptedImporter + { + [Tooltip("Flags controlling how the SQLite connection should be opened. 'ReadWrite' and 'Create' flags will be ignored, since SQLite assets are read-only.")] + [SerializeField] private SQLiteOpenFlags _openFlags = SQLiteOpenFlags.ReadOnly; + + [Tooltip("Whether to store DateTime properties as ticks (true) or strings (false).")] + [SerializeField] private bool _storeDateTimeAsTicks = true; + + [Tooltip("Name of the file created for the database inside Streaming Assets folder during builds.\n\n" + + "If empty, the database bytes will be stored in the asset itself.\n\n" + + "Loading databases from Streaming Assets is not supported in Android and WebGL platforms.")] + [SerializeField] private string _streamingAssetsPath; + + public override void OnImportAsset(AssetImportContext ctx) + { + var asset = ScriptableObject.CreateInstance(); + asset.OpenFlags = _openFlags; + asset.StoreDateTimeAsTicks = _storeDateTimeAsTicks; + asset.Bytes = File.ReadAllBytes(ctx.assetPath); + asset.StreamingAssetsPath = _streamingAssetsPath; + ctx.AddObjectToAsset("sqlite", asset); + ctx.SetMainObject(asset); + } + } +} diff --git a/Editor/SQLiteAssetImporter.cs.meta b/Editor/SQLiteAssetImporter.cs.meta new file mode 100644 index 0000000..ec5f3af --- /dev/null +++ b/Editor/SQLiteAssetImporter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a82a308980f2947468fbbb0695613ed2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/README.md b/README.md index b3f0e19..90c7374 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,13 @@ This package provides the excelent [SQLite-net](https://github.com/praeclarum/sq + Enabled modules: [R\*Tree](https://sqlite.org/rtree.html), [Geopoly](https://sqlite.org/geopoly.html), [FTS5](https://sqlite.org/fts5.html), [Built-In Math Functions](https://www.sqlite.org/lang_mathfunc.html) + Supports Windows, Linux, macOS, WebGL, Android, iOS, tvOS and visionOS platforms + Supports persisting data in WebGL builds by using a [custom VFS backed by Indexed DB](https://github.com/gilzoide/idbvfs). - +- [SQLiteAsset](Runtime/SQLiteAsset.cs): read-only SQLite database Unity assets. + + Files with the extensions ".sqlite", ".sqlite2" and ".sqlite3" will be imported as SQLite database assets. + + Use the `CreateConnection()` method for connecting to the database provided by the asset. + Make sure to `Dispose()` of any connections you create. + + SQLite assets may be loaded from Streaming Assets folder or from memory, depending on the value of their "Streaming Assets Path" property. + + **Warning**: Android and WebGL platforms don't support loading SQLite databases from Streaming Assets and will always load them in memory. + + `SQLiteConnection.SerializeToAsset` extension method for serializing a database to an instance of `SQLiteAsset`. ## Optional packages - [SQLite Asset](https://github.com/gilzoide/unity-sqlite-asset): read-only SQLite database assets for Unity with scripted importer for ".sqlite", ".sqlite2" and ".sqlite3" files From 709e19fc8cef9cddcea9db0ed99958405be78f1c Mon Sep 17 00:00:00 2001 From: gilzoide Date: Sat, 28 Jun 2025 12:59:28 -0300 Subject: [PATCH 04/11] Add copyright notice to new files --- Editor/SQLiteAssetBuildProcessor.cs | 21 +++++++++++++++++++++ Editor/SQLiteAssetEditor.cs | 21 +++++++++++++++++++++ Editor/SQLiteAssetImporter.cs | 21 +++++++++++++++++++++ Runtime/SQLiteAsset.cs | 22 +++++++++++++++++++++- 4 files changed, 84 insertions(+), 1 deletion(-) diff --git a/Editor/SQLiteAssetBuildProcessor.cs b/Editor/SQLiteAssetBuildProcessor.cs index a659975..58fb40f 100644 --- a/Editor/SQLiteAssetBuildProcessor.cs +++ b/Editor/SQLiteAssetBuildProcessor.cs @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2025 Gil Barbosa Reis + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ #if !UNITY_ANDROID && !UNITY_WEBGL using System; using System.Collections.Generic; diff --git a/Editor/SQLiteAssetEditor.cs b/Editor/SQLiteAssetEditor.cs index 53159f7..479a7ee 100644 --- a/Editor/SQLiteAssetEditor.cs +++ b/Editor/SQLiteAssetEditor.cs @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2025 Gil Barbosa Reis + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ using System.Collections.Generic; using UnityEditor; using UnityEngine; diff --git a/Editor/SQLiteAssetImporter.cs b/Editor/SQLiteAssetImporter.cs index b1d3a3b..2818416 100644 --- a/Editor/SQLiteAssetImporter.cs +++ b/Editor/SQLiteAssetImporter.cs @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2025 Gil Barbosa Reis + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ using System.IO; #if UNITY_2020_2_OR_NEWER using UnityEditor.AssetImporters; diff --git a/Runtime/SQLiteAsset.cs b/Runtime/SQLiteAsset.cs index b852b79..dfb7431 100644 --- a/Runtime/SQLiteAsset.cs +++ b/Runtime/SQLiteAsset.cs @@ -1,5 +1,25 @@ +/* + * Copyright (c) 2025 Gil Barbosa Reis + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ using System; -using SQLite; using UnityEngine; namespace SQLite From 72b69db2fe919ac993d83c73e108ff4d31209c30 Mon Sep 17 00:00:00 2001 From: gilzoide Date: Sat, 28 Jun 2025 13:13:03 -0300 Subject: [PATCH 05/11] Add CSV scripted importer that imports a SQLiteAsset --- Editor/Csv.meta | 8 + Editor/Csv/SQLiteAssetCsvImporter.cs | 98 ++++++++++++ Editor/Csv/SQLiteAssetCsvImporter.cs.meta | 11 ++ README.md | 7 +- Runtime/Csv.meta | 8 + Runtime/Csv/CsvException.cs | 30 ++++ Runtime/Csv/CsvException.cs.meta | 11 ++ Runtime/Csv/CsvReader.cs | 183 ++++++++++++++++++++++ Runtime/Csv/CsvReader.cs.meta | 11 ++ Runtime/SQLiteConnectionExtensions.cs | 64 +++++++- 10 files changed, 425 insertions(+), 6 deletions(-) create mode 100644 Editor/Csv.meta create mode 100644 Editor/Csv/SQLiteAssetCsvImporter.cs create mode 100644 Editor/Csv/SQLiteAssetCsvImporter.cs.meta create mode 100644 Runtime/Csv.meta create mode 100644 Runtime/Csv/CsvException.cs create mode 100644 Runtime/Csv/CsvException.cs.meta create mode 100644 Runtime/Csv/CsvReader.cs create mode 100644 Runtime/Csv/CsvReader.cs.meta diff --git a/Editor/Csv.meta b/Editor/Csv.meta new file mode 100644 index 0000000..980ee06 --- /dev/null +++ b/Editor/Csv.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a2c02e692b7cf4b58911c97897f8176a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Csv/SQLiteAssetCsvImporter.cs b/Editor/Csv/SQLiteAssetCsvImporter.cs new file mode 100644 index 0000000..eaf8b2f --- /dev/null +++ b/Editor/Csv/SQLiteAssetCsvImporter.cs @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2025 Gil Barbosa Reis + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +using System.IO; +using SQLite.Csv; +#if UNITY_2020_2_OR_NEWER +using UnityEditor.AssetImporters; +#else +using UnityEditor.Experimental.AssetImporters; +#endif +using UnityEngine; + +namespace SQLite.Editor.Csv +{ + [ScriptedImporter(0, null, new[] { "csv" })] + public class SQLiteAssetCsvImporter : ScriptedImporter + { + [Header("SQLite asset options")] + [Tooltip("Name of the table that will be created for holding the CSV data inside the database.")] + [SerializeField] private string _tableName = "data"; + + [Tooltip("Flags controlling how the SQLite connection should be opened. 'ReadWrite' and 'Create' flags will be ignored, since SQLite assets are read-only.")] + [SerializeField] private SQLiteOpenFlags _openFlags = SQLiteOpenFlags.ReadOnly; + + [Tooltip("Whether to store DateTime properties as ticks (true) or strings (false).")] + [SerializeField] private bool _storeDateTimeAsTicks = true; + + [Tooltip("Name of the file created for the database inside Streaming Assets folder during builds.\n\n" + + "If empty, the database bytes will be stored in the asset itself.\n\n" + + "Loading databases from Streaming Assets is not supported in Android and WebGL platforms.")] + [SerializeField] private string _streamingAssetsPath; + + + [Header("CSV options")] + [Tooltip("Which separator character will be used when parsing the CSV file.")] + [SerializeField] private CsvReader.SeparatorChar _CSVSeparator = CsvReader.SeparatorChar.Comma; + + [Tooltip("If true, the original CSV file will also be imported as a TextAsset")] + [SerializeField] private bool _importCSVTextAsset = false; + + [Header("Additional SQL")] + [Tooltip("SQL script that will be run before reading CSV data. Use this for configuring the generated database using PRAGMAs like 'page_size'.")] + [SerializeField, Multiline] private string _SQLBeforeReadingCSV = ""; + + [Tooltip("SQL script that will be run after reading CSV data. Use this for changing the table's schema, creating indices, etc.")] + [SerializeField, Multiline] private string _SQLAfterReadingCSV = ""; + + public override void OnImportAsset(AssetImportContext ctx) + { + SQLiteAsset asset; + using (var tempDb = new SQLiteConnection("")) + using (var file = File.OpenRead(assetPath)) + using (var stream = new StreamReader(file)) + { + if (!string.IsNullOrWhiteSpace(_SQLBeforeReadingCSV)) + { + tempDb.Execute(_SQLBeforeReadingCSV); + } + tempDb.ImportCsvToTable(_tableName, stream, _CSVSeparator); + if (!string.IsNullOrWhiteSpace(_SQLAfterReadingCSV)) + { + tempDb.Execute(_SQLAfterReadingCSV); + } + + asset = tempDb.SerializeToAsset(null, _openFlags, _storeDateTimeAsTicks, _streamingAssetsPath); + } + ctx.AddObjectToAsset("sqlite", asset); + ctx.SetMainObject(asset); + + if (_importCSVTextAsset) + { + var textAsset = new TextAsset(File.ReadAllText(assetPath)) + { + name = $"{Path.GetFileNameWithoutExtension(assetPath)}", + }; + ctx.AddObjectToAsset("text", textAsset); + } + } + } +} diff --git a/Editor/Csv/SQLiteAssetCsvImporter.cs.meta b/Editor/Csv/SQLiteAssetCsvImporter.cs.meta new file mode 100644 index 0000000..7e88486 --- /dev/null +++ b/Editor/Csv/SQLiteAssetCsvImporter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fc7f33370e31747c8b998403bea5e202 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/README.md b/README.md index 90c7374..43a6efe 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ This package provides the excelent [SQLite-net](https://github.com/praeclarum/sq + Both synchronous and asynchronous APIs are available + `SQLiteConnection.Serialize` extension method for serializing a database to `byte[]` (reference: [SQLite Serialization](https://www.sqlite.org/c3ref/serialize.html)). + `SQLiteConnection.Deserialize` extension method for deserializing memory (`byte[]`, `NativeArray` or `ReadOnlySpan`) into an open database (reference: [SQLite Deserialization](https://www.sqlite.org/c3ref/deserialize.html)). + + `SQLiteConnection.ImportCsvToTable` extension method for importing a CSV text stream as a new table inside the database. - [SQLite3 Multiple Ciphers 2.1.3](https://github.com/utelle/SQLite3MultipleCiphers/releases/tag/v2.1.3) (based on [SQLite 3.50.1](https://sqlite.org/releaselog/3_50_1.html)) + Supports encrypted databases + Enabled modules: [R\*Tree](https://sqlite.org/rtree.html), [Geopoly](https://sqlite.org/geopoly.html), [FTS5](https://sqlite.org/fts5.html), [Built-In Math Functions](https://www.sqlite.org/lang_mathfunc.html) @@ -16,17 +17,13 @@ This package provides the excelent [SQLite-net](https://github.com/praeclarum/sq + Supports persisting data in WebGL builds by using a [custom VFS backed by Indexed DB](https://github.com/gilzoide/idbvfs). - [SQLiteAsset](Runtime/SQLiteAsset.cs): read-only SQLite database Unity assets. + Files with the extensions ".sqlite", ".sqlite2" and ".sqlite3" will be imported as SQLite database assets. + + ".csv" files can be imported as SQLite database assets by changing the importer to `SQLite.Editor.Csv.SQLiteAssetCsvImporter` in the Inspector. + Use the `CreateConnection()` method for connecting to the database provided by the asset. Make sure to `Dispose()` of any connections you create. + SQLite assets may be loaded from Streaming Assets folder or from memory, depending on the value of their "Streaming Assets Path" property. + **Warning**: Android and WebGL platforms don't support loading SQLite databases from Streaming Assets and will always load them in memory. + `SQLiteConnection.SerializeToAsset` extension method for serializing a database to an instance of `SQLiteAsset`. -## Optional packages -- [SQLite Asset](https://github.com/gilzoide/unity-sqlite-asset): read-only SQLite database assets for Unity with scripted importer for ".sqlite", ".sqlite2" and ".sqlite3" files -- [SQLite Asset - CSV](https://github.com/gilzoide/unity-sqlite-asset-csv): easily import ".csv" files as read-only SQLite database assets - - ## How to install Either: - Use the [openupm registry](https://openupm.com/) and install this package using the [openupm-cli](https://github.com/openupm/openupm-cli): diff --git a/Runtime/Csv.meta b/Runtime/Csv.meta new file mode 100644 index 0000000..009e3c9 --- /dev/null +++ b/Runtime/Csv.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b1c2a8809fb9c4735a75582f79b026d4 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Csv/CsvException.cs b/Runtime/Csv/CsvException.cs new file mode 100644 index 0000000..334d096 --- /dev/null +++ b/Runtime/Csv/CsvException.cs @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2025 Gil Barbosa Reis + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +using System; + +namespace SQLite.Csv +{ + public class CsvException : Exception + { + public CsvException(string message) : base(message) {} + } +} diff --git a/Runtime/Csv/CsvException.cs.meta b/Runtime/Csv/CsvException.cs.meta new file mode 100644 index 0000000..2fb9c04 --- /dev/null +++ b/Runtime/Csv/CsvException.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 267285bfe909149a9842f0bc1341cf70 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Csv/CsvReader.cs b/Runtime/Csv/CsvReader.cs new file mode 100644 index 0000000..872239f --- /dev/null +++ b/Runtime/Csv/CsvReader.cs @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2025 Gil Barbosa Reis + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace SQLite.Csv +{ + public static class CsvReader + { + public enum SeparatorChar + { + Comma, + Semicolon, + Tabs, + } + + /// + /// Parse a stream of CSV-formatted data. + /// + /// Stream of CSV-formatted data. + /// Character used for separating fields. + /// Maximum field size allowed. + /// + /// The enumeration returns each field's contents, even if it is empty. + /// is returned at the end of the lines, meaning a new row will start next. + /// Empty lines are ignored and will not be enumerated. + /// + /// Thrown if is null. + /// Thrown if any field size is greater than . + public static IEnumerable ParseStream(TextReader stream, SeparatorChar separator = SeparatorChar.Comma, int maxFieldSize = int.MaxValue) + { + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + SkipEmptyLines(stream); + if (stream.Peek() < 0) + { + yield break; + } + + bool insideQuotes = false; + var stringBuilder = new StringBuilder(); + while (true) + { + int c = stream.Read(); + switch (c) + { + case '\r': + if (!insideQuotes && stream.Peek() == '\n') + { + stream.Read(); + goto case '\n'; + } + else + { + goto default; + } + + case '\n': + if (!insideQuotes) + { + yield return stringBuilder.ToString(); + stringBuilder.Clear(); + yield return null; + + SkipEmptyLines(stream); + if (stream.Peek() < 0) + { + yield break; + } + } + else + { + goto default; + } + break; + + case ',': + if (!insideQuotes && separator == SeparatorChar.Comma) + { + yield return stringBuilder.ToString(); + stringBuilder.Clear(); + } + else + { + goto default; + } + break; + + case ';': + if (!insideQuotes && separator == SeparatorChar.Semicolon) + { + yield return stringBuilder.ToString(); + stringBuilder.Clear(); + } + else + { + goto default; + } + break; + + case '\t': + if (!insideQuotes && separator == SeparatorChar.Tabs) + { + yield return stringBuilder.ToString(); + stringBuilder.Clear(); + } + else + { + goto default; + } + break; + + case '"': + if (insideQuotes && stream.Peek() == '"') + { + stream.Read(); + goto default; + } + else + { + insideQuotes = !insideQuotes; + } + break; + + case < 0: + yield return stringBuilder.ToString(); + yield return null; + yield break; + + default: + if (stringBuilder.Length >= maxFieldSize) + { + throw new CsvException("Field size is greater than maximum allowed size."); + } + stringBuilder.Append((char) c); + break; + } + } + } + + private static void SkipEmptyLines(TextReader streamReader) + { + while (true) + { + int c = streamReader.Peek(); + switch (c) + { + case '\n': + case '\r': + streamReader.Read(); + continue; + + default: + return; + } + } + } + } +} diff --git a/Runtime/Csv/CsvReader.cs.meta b/Runtime/Csv/CsvReader.cs.meta new file mode 100644 index 0000000..3df2246 --- /dev/null +++ b/Runtime/Csv/CsvReader.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6af882ccfbbe24a8fbc2c99371ea98cf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SQLiteConnectionExtensions.cs b/Runtime/SQLiteConnectionExtensions.cs index 1a1f81a..0c3645c 100644 --- a/Runtime/SQLiteConnectionExtensions.cs +++ b/Runtime/SQLiteConnectionExtensions.cs @@ -20,7 +20,10 @@ * SOFTWARE. */ using System; +using System.Collections.Generic; +using System.IO; using System.Runtime.InteropServices; +using SQLite.Csv; #if UNITY_2018_1_OR_NEWER using Unity.Collections; using Unity.Collections.LowLevel.Unsafe; @@ -41,7 +44,7 @@ public static byte[] Serialize(this SQLiteConnection db, string schema = null) try { var bytes = new byte[size]; - Marshal.Copy(buffer, bytes, 0, (int) size); + Marshal.Copy(buffer, bytes, 0, (int)size); return bytes; } finally @@ -119,5 +122,64 @@ public static SQLiteConnection Deserialize(this SQLiteConnection db, ReadOnlySpa return db; } #endif + + /// + /// Import a CSV data stream into the table named inside the database. + /// The table will be created if it doesn't exist yet. + /// + /// Open database connection + /// Name of the table that should be filled with data from the CSV data stream. + /// Data stream with CSV-formatted contents. + /// Separator used for parsing the CSV. Defaults to comma. + /// Maximum field size allowed. + /// Thrown if any of , and are null. + /// Thrown if an error is found while parsing the CSV data. + public static void ImportCsvToTable(this SQLiteConnection db, string tableName, TextReader csvStream, CsvReader.SeparatorChar separator = CsvReader.SeparatorChar.Comma, int maxFieldSize = int.MaxValue) + { + if (db == null) + { + throw new ArgumentNullException(nameof(db)); + } + if (string.IsNullOrWhiteSpace(tableName)) + { + throw new ArgumentNullException(nameof(tableName)); + } + if (csvStream == null) + { + throw new ArgumentNullException(nameof(csvStream)); + } + + var columns = new List(); + bool parsingHeader = true; + db.RunInTransaction(() => + { + foreach (string field in CsvReader.ParseStream(csvStream, separator, maxFieldSize)) + { + if (field == null) // newline + { + string joinedColumns = string.Join(", ", columns); + if (parsingHeader) + { + db.Execute($"CREATE TABLE IF NOT EXISTS {tableName} ({joinedColumns})"); + parsingHeader = false; + } + else + { + db.Execute($"INSERT INTO {tableName} VALUES ({joinedColumns})"); + } + columns.Clear(); + } + else + { + if (parsingHeader && string.IsNullOrWhiteSpace(field)) + { + throw new CsvException("Header cannot have empty column name."); + } + + columns.Add(SQLiteConnection.Quote(field)); + } + } + }); + } } } From 65324b565d0246a26034ad7b29e58855079df21c Mon Sep 17 00:00:00 2001 From: gilzoide Date: Sat, 28 Jun 2025 13:15:53 -0300 Subject: [PATCH 06/11] Update README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 43a6efe..c589291 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ This package provides the excelent [SQLite-net](https://github.com/praeclarum/sq + Use the `CreateConnection()` method for connecting to the database provided by the asset. Make sure to `Dispose()` of any connections you create. + SQLite assets may be loaded from Streaming Assets folder or from memory, depending on the value of their "Streaming Assets Path" property. - + **Warning**: Android and WebGL platforms don't support loading SQLite databases from Streaming Assets and will always load them in memory. + + **Note**: Android and WebGL platforms don't support loading SQLite databases from Streaming Assets and will always load them in memory. + `SQLiteConnection.SerializeToAsset` extension method for serializing a database to an instance of `SQLiteAsset`. ## How to install From 44049d377dde51a28f8bb4aedc9b322e85c5166d Mon Sep 17 00:00:00 2001 From: gilzoide Date: Sat, 28 Jun 2025 13:16:35 -0300 Subject: [PATCH 07/11] Update copyright notice year --- Runtime/SQLiteAsyncExtensions.cs | 21 +++++++++++++++++++++ Runtime/SQLiteConnectionExtensions.cs | 2 +- Runtime/SQLiteExtensions.cs | 2 +- Runtime/SQLitePreparedStatement.cs | 2 +- 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/Runtime/SQLiteAsyncExtensions.cs b/Runtime/SQLiteAsyncExtensions.cs index 647e1c2..f03727e 100644 --- a/Runtime/SQLiteAsyncExtensions.cs +++ b/Runtime/SQLiteAsyncExtensions.cs @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2025 Gil Barbosa Reis + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ using System.Threading.Tasks; using UnityEngine; diff --git a/Runtime/SQLiteConnectionExtensions.cs b/Runtime/SQLiteConnectionExtensions.cs index 0c3645c..d6a4632 100644 --- a/Runtime/SQLiteConnectionExtensions.cs +++ b/Runtime/SQLiteConnectionExtensions.cs @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Gil Barbosa Reis + * Copyright (c) 2025 Gil Barbosa Reis * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/Runtime/SQLiteExtensions.cs b/Runtime/SQLiteExtensions.cs index e682b16..56bc6fc 100644 --- a/Runtime/SQLiteExtensions.cs +++ b/Runtime/SQLiteExtensions.cs @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Gil Barbosa Reis + * Copyright (c) 2025 Gil Barbosa Reis * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/Runtime/SQLitePreparedStatement.cs b/Runtime/SQLitePreparedStatement.cs index 3ff47a6..15be06a 100644 --- a/Runtime/SQLitePreparedStatement.cs +++ b/Runtime/SQLitePreparedStatement.cs @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Gil Barbosa Reis + * Copyright (c) 2025 Gil Barbosa Reis * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal From aaa99e9c29db8854321ed44b4869fa5a2a3282d5 Mon Sep 17 00:00:00 2001 From: gilzoide Date: Sat, 28 Jun 2025 13:19:19 -0300 Subject: [PATCH 08/11] Update minimum Unity version to 2021.2 --- Editor/Csv/SQLiteAssetCsvImporter.cs | 4 ---- Editor/SQLiteAssetImporter.cs | 4 ---- Runtime/SQLiteConnectionExtensions.cs | 6 ------ package.json | 5 +++-- 4 files changed, 3 insertions(+), 16 deletions(-) diff --git a/Editor/Csv/SQLiteAssetCsvImporter.cs b/Editor/Csv/SQLiteAssetCsvImporter.cs index eaf8b2f..5f57281 100644 --- a/Editor/Csv/SQLiteAssetCsvImporter.cs +++ b/Editor/Csv/SQLiteAssetCsvImporter.cs @@ -21,11 +21,7 @@ */ using System.IO; using SQLite.Csv; -#if UNITY_2020_2_OR_NEWER using UnityEditor.AssetImporters; -#else -using UnityEditor.Experimental.AssetImporters; -#endif using UnityEngine; namespace SQLite.Editor.Csv diff --git a/Editor/SQLiteAssetImporter.cs b/Editor/SQLiteAssetImporter.cs index 2818416..9c6ce32 100644 --- a/Editor/SQLiteAssetImporter.cs +++ b/Editor/SQLiteAssetImporter.cs @@ -20,11 +20,7 @@ * SOFTWARE. */ using System.IO; -#if UNITY_2020_2_OR_NEWER using UnityEditor.AssetImporters; -#else -using UnityEditor.Experimental.AssetImporters; -#endif using UnityEngine; namespace SQLite.Editor diff --git a/Runtime/SQLiteConnectionExtensions.cs b/Runtime/SQLiteConnectionExtensions.cs index d6a4632..0d1b812 100644 --- a/Runtime/SQLiteConnectionExtensions.cs +++ b/Runtime/SQLiteConnectionExtensions.cs @@ -24,10 +24,8 @@ using System.IO; using System.Runtime.InteropServices; using SQLite.Csv; -#if UNITY_2018_1_OR_NEWER using Unity.Collections; using Unity.Collections.LowLevel.Unsafe; -#endif using UnityEngine; namespace SQLite @@ -78,7 +76,6 @@ public static SQLiteConnection Deserialize(this SQLiteConnection db, byte[] buff return db; } -#if UNITY_2018_1_OR_NEWER public static SQLiteConnection Deserialize(this SQLiteConnection db, NativeArray buffer, string schema = null, SQLite3.DeserializeFlags flags = SQLite3.DeserializeFlags.None) { return Deserialize(db, buffer, buffer.Length, schema, flags); @@ -97,9 +94,7 @@ public static SQLiteConnection Deserialize(this SQLiteConnection db, NativeArray } return db; } -#endif -#if UNITY_2021_2_OR_NEWER public static SQLiteConnection Deserialize(this SQLiteConnection db, ReadOnlySpan buffer, string schema = null, SQLite3.DeserializeFlags flags = SQLite3.DeserializeFlags.None) { return Deserialize(db, buffer, buffer.Length, schema, flags); @@ -121,7 +116,6 @@ public static SQLiteConnection Deserialize(this SQLiteConnection db, ReadOnlySpa } return db; } -#endif /// /// Import a CSV data stream into the table named inside the database. diff --git a/package.json b/package.json index 969ffd1..9494b99 100644 --- a/package.json +++ b/package.json @@ -14,5 +14,6 @@ "description": "Demonstrates a simple REPL for SQL statements.", "path": "Samples~/REPL" } - ] -} + ], + "unity": "2021.2" +} \ No newline at end of file From 1bf6d60235fda1659e4347e7fac8d399f0a0b6b4 Mon Sep 17 00:00:00 2001 From: gilzoide Date: Sat, 28 Jun 2025 13:31:48 -0300 Subject: [PATCH 09/11] Update README [skip ci] --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index df38830..8afe488 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ ## [Unreleased](https://github.com/gilzoide/unity-sqlite-net/compare/1.2.4...HEAD) ### Added - Support for encrypting / decrypting databases by using [SQLite3 Multiple Ciphers](https://utelle.github.io/SQLite3MultipleCiphers/) implementation +- [SQLiteAsset](Runtime/SQLiteAsset.cs): read-only SQLite database Unity assets. + Files with the extensions ".sqlite", ".sqlite2" and ".sqlite3" will be imported as SQLite database assets. + ".csv" files can be imported as SQLite database assets by changing the importer to `SQLite.Editor.Csv.SQLiteAssetCsvImporter` in the Inspector. +- `SQLiteConnection.SerializeToAsset` extension method for serializing a database to an instance of `SQLiteAsset`. +- `SQLiteConnection.ImportCsvToTable` extension method for importing a CSV text stream as a new table inside the database. ### Changed - Update SQLite to 3.50.1 From c0d134e0b66c918cb071cd7d810e5fae82b26d55 Mon Sep 17 00:00:00 2001 From: gilzoide Date: Sat, 28 Jun 2025 13:34:54 -0300 Subject: [PATCH 10/11] Don't show database size in bytes when editing multiple objects --- Editor/SQLiteAssetEditor.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/Editor/SQLiteAssetEditor.cs b/Editor/SQLiteAssetEditor.cs index 479a7ee..841c959 100644 --- a/Editor/SQLiteAssetEditor.cs +++ b/Editor/SQLiteAssetEditor.cs @@ -46,20 +46,18 @@ public void Deconstruct(out string name, out string sql) public override void OnInspectorGUI() { DrawDefaultInspector(); - EditorGUILayout.Space(); - - using (new EditorGUI.DisabledScope(true)) - { - EditorGUILayout.TextField("Database size in bytes", EditorUtility.FormatBytes(((SQLiteAsset) target).Bytes.Length)); - } - if (serializedObject.isEditingMultipleObjects) { return; } EditorGUILayout.Space(); + using (new EditorGUI.DisabledScope(true)) + { + EditorGUILayout.TextField("Database size in bytes", EditorUtility.FormatBytes(((SQLiteAsset) target).Bytes.Length)); + } + EditorGUILayout.Space(); using (new EditorGUI.DisabledScope(true)) using (var db = ((SQLiteAsset) target).CreateConnection()) { From 777ca62819d9a30427a81d6566e037ea7af29ac3 Mon Sep 17 00:00:00 2001 From: gilzoide Date: Sat, 28 Jun 2025 13:35:56 -0300 Subject: [PATCH 11/11] Use tuple instead of creating class TableInfo --- Editor/SQLiteAssetEditor.cs | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/Editor/SQLiteAssetEditor.cs b/Editor/SQLiteAssetEditor.cs index 841c959..8a0b666 100644 --- a/Editor/SQLiteAssetEditor.cs +++ b/Editor/SQLiteAssetEditor.cs @@ -29,18 +29,6 @@ namespace SQLite.Editor [CanEditMultipleObjects] public class SQLiteAssetEditor : UnityEditor.Editor { - private class TableInfo - { - public string Name { get; set; } - public string Sql { get; set; } - - public void Deconstruct(out string name, out string sql) - { - name = Name; - sql = Sql; - } - } - [SerializeField] private List _expandedTables = new List(); public override void OnInspectorGUI() @@ -63,7 +51,7 @@ public override void OnInspectorGUI() { EditorGUILayout.LabelField("Tables", EditorStyles.boldLabel); EditorGUI.indentLevel++; - foreach ((string name, string sql) in db.Query("SELECT name, sql FROM SQLite_schema WHERE type = 'table'")) + foreach ((string name, string sql) in db.Query<(string, string)>("SELECT name, sql FROM SQLite_schema WHERE type = 'table'")) { bool previouslyExpanded = _expandedTables.Contains(name); bool expanded = EditorGUILayout.Foldout(previouslyExpanded, name, true);