Small library for building SQL query strings use PHP

Samples

// query template, probably loaded from external file 
$template = "select emp.* from employee emp" . 
	" join departments dep on emp.id_department = dep.id" . 
	" @{where}" . 
	" @{order}" . 
	" limit :limit offset :_offset";
// create "where" clause
$where = \Query\Expressions::where()
	->andExpr("emp.surname = :surname")
	->andExpr("emp.name like :name")
	->andExpr(
		\Query\Expressions::orExpr(
			\Query\Expressions::expr("emp.salary < :salary")->andExpr("emp.position in (:positionList)"),
			\Query\Expressions::not("emp.age < :ageThreshold")
		)
	)
	->andExpr("status != 'ARCHIVED'");
// create "order" clause
$order = \Query\Expressions::orderBy()->add("dep.id desc")->add("cust.salary");
// create builder from template and fill clauses
$sql = \Query\QueryBuilder::query($template)
	->set("where", $where)
	->set("order", $order)
	->build();

//equal, notequal, greaterthan, lessthan, in, like

$expr = \Query\Expressions::where()
			->andExpr(new \Query\EqualExpr("surname", "surname"))
			->andExpr(new \Query\LikeExpr("name", "name"))
			->andExpr(
				\Query\Expressions::orExpr(
					\Query\Expressions::expr(new \Query\LessThanExpr("salary", "5000"))
						->andExpr(new \Query\InExpr("position", "1,2,3"))
						->andExpr(new \Query\InExpr("position", array(1,2.6,"3", "a"))),
					\Query\Expressions::not(new \Query\GreaterThanExpr("age", "`ageThreshold`"))
				)
			)
			->andExpr(new \Query\NotEqualExpr("status", "ARCHIVED"));

		$columns = array(
			"surname" => "prefix_surname",
			"name" => "prefix_name",
		);
		$sql = \Query\MysqlQueryBuilder::query($expr, $columns)->build();
		$sqlResult = >>>STRBLOCK
where prefix_surname = 'surname'
 and prefix_name like 'name'
 and ((salary < 5000 and position in (1,2,3) and position in (1,2.6,3,'a')) or (not (age > `ageThreshold`)))
 and status != 'ARCHIVED'
STRBLOCK;

//operator : evaluate
$expr = \Query\Expressions::expr(new \Query\EqualExpr("surname", "myname"));
$dict = array();
$dict['surname'] = 'myname';
$expr->evaluate($dict);

$expr1 = $expr->andExpr(new \Query\EqualExpr("surname", "yourname"));
$expr->evaluate($dict);
$expr2 = $expr->andExpr(new \Query\NotEqualExpr("surname", "yourname"));
$expr2->evaluate($dict);
$dict['salary'] = 6000;
$expr3 = $expr2->andExpr(new \Query\GreaterThanExpr("salary", "5000"));
$expr3->evaluate($dict);
$expr4 = $expr2->andExpr(new \Query\LessThanExpr("salary", "5000"));
$expr4->evaluate($dict);

$dict['position'] = 2;
$dict['age'] = 25;
$dict['ageThreshold'] = 45;

$expr5 = \Query\Expressions::expr(new \Query\EqualExpr("surname", "myname"))
    ->andExpr(new \Query\NotEqualExpr("surname", "yourname"))
    ->andExpr(new \Query\GreaterThanExpr("salary", "5000"))
    ->andExpr(new \Query\LessThanExpr("salary", "7000"))
    ->andExpr(new \Query\OrExpr(
            new \Query\InExpr("position", "1,2,3"),
            new \Query\NotExpr(
                new \Query\InExpr("position", array(5, 6, 7))
            )
        )
    )
    ->andExpr(\Query\Expressions::not(new \Query\GreaterThanExpr("age", "`ageThreshold`")));
$expr5->evaluate($dict);

请参见测试用例:QueryTest.php

github: PHP query build strings

 

一个很容易掉坑的Android Memory Leak问题

Android自从某个版本之后错误率一直居高不下,接近1个点的crash率让人抬不起头来,虽然中间试着去找出问题根源,但时间较短,每次都一头雾水无功而返。

五一正好碰到项目中间相对较长的空歇期,于是下定决心一定要把这事给弄出个眉目,于是花了断断续续两天时间终于理论上搞定了。撒花~撒花~~~。

中间各种排除法、工具法、思考法不再赘叙,最终的问题出在很不起眼的一个调用:View::setTag(index, Object)。

这是个很二的实现,google+源码,发现这货把index + Object存在了一个static WeakHashMap中,key是调用的View本身。乍看没问题?但是,当你的Object是一个强引用指向调用的View,那么,除非手动删除,否则该View就不会被自动回收,内存泄漏就此产生了。

而View::setTag(index, Object)有一个重载的方法叫View::setTag(Object),这货却是把Object作为成员变量给存了下来,于是这个方法是没有问题的。坑爹的Google!

结论:尽量不要在setTag(index, Object)中把指向View的对象设进去,实在没办法记得找地方set为null。

相信下个版本的android crash率会让人振奋的!喔哈哈哈哈~~~~

iOS 火星坐标相关整理及解决方案汇总

这几天处理定位相关的代码,彻彻底底的被火星坐标恶心到了。

恶心列表

  1. 从 CLLocationManager 取出来的经纬度放到 mapView 上显示,是错的!
  2. 从 CLLocationManager 取出来的经纬度去 Google Maps API 做逆地址解析,当然是错的!
  3. 从 MKMapView 取出来的经纬度去 Google Maps API 做逆地址解析终于对了。去百度地图API做逆地址解析,依旧是错的!
  4. 从上面两处取的经纬度放到百度地图上显示都是错的!错的!的!

当时我还不知道火星坐标、XX坐标,大骂苹果SB(我错了)…… 如果你碰到上述情况,接着往下看。

名词解释:

地球坐标 (WGS84)

  • 国际标准,GPS标准从 GPS 设备中取出的原始数据是就是这个
  • 国际地图提供商一般使用的也是这个

火星坐标 (GCJ-02)

  • 中国标准,行货 GPS 设备取出的最终数据是这个
  • 国家龟腚: 国内出版的各种地图系统(包括电子形式),必须至少采用GCJ-02对地理位置进行首次加密。

百度坐标 (BD-09)

  • 百度标准,百度 SDK,地图,Geocoding 用的都是这个。

开发时所面临的现状

获取经纬度(GPS)

  • 火星坐标
    • MKMapView
  • 地球坐标
    • CLLocationManager

显示经纬度(地图)

  • 火星坐标
    • iOS 地图
    • Gogole地图
    • 搜搜、阿里云、高德地图
  • 地球坐标
    • Google 卫星地图(国外地图应该都是……)
  • 百度坐标
    • 百度地图

推荐的解决方案:

  • 既然是在国内,存储一律用火星坐标,这样在使用国内地图显示时最方便(用百度地图显示时可以一次转换取得)
  • CLLocationManager 拿到的 CLLocation 转为火星坐标,MKMapView 不用处理
  • 使用地图 API 进行 地址解析/逆地址解析(Geocoding) 时注意相应使用相应地图商的坐标系

附上相应的转换算法

iOS 平台的转换算法的已经封装了一个 Category,在这里 CLLocation+Sino

地图坐标 to 火星坐标

火星坐标 to 地图坐标

火星坐标 vs 百度坐标

总结

  • iOS SDK 的做法还是比较合理的,毕竟他是一个国际化的平台。CLLocationManager 提供地球坐标,这样显示国外地图商的地图服务没问题,碰到火星地图,转一下就好,逆之则没那么容易。而 MKMapView 则与 iOS 地图展示相关,国内地图必须使用火星坐标
  • 本人只是想用户使用 app 时能简简单单定位准确,而不是飞檐走壁狐死首丘。本文只做技术讨论,不敢侵犯任何个人、团体、政党、国家、星球权利,任何XXX对此文不满,请留言,我立刻删之

links

附上 Blog 原文链接:i0xbean.com

jenkins iOS build for chencang

1、多个工程依赖(或有pod)build最方便的方式 workspace。

方法:Manage Schemes =>   Show (选中) | Scheme (Chencang) | Container (Chencang Workspace)  | Shared (选中)。

此中 Chencang 为App 主工程。

2、Pod 注意升级 (gem update pod 或 sudo gem update pod)。可能还需要注意 Ruby 的版本(当前是 1.8.7)是否够了。

3、使用 Ad Hoc mobileprovision。可以上传到 testflight。

4、CodeSign 的 Ad Hoc 选择 3 。并且注意  PROVISIONING_PROFILE = “XXXXXXXXXXXXXXX”; 注意改为 PROVISIONING_PROFILE = ““ 或删除这一行。否则报错: ” Code Sign error: Provisioning profile can’t be found ”

5、如果是单个 Project ,填写 Xcode Project File 属性,注意填全文件名: Chencang.xcodeproj。至于 Xcode Workspace File  填 Chencang 就行了。

6、这次的Chencang 居然是用了 git(github) submodules ,这个东西,要使用 sourcetree 自动(pull 主branch就自动更新 sub brance)更新的话,最方便的方法就是  github ssh-key 访问方式: git@github.com:yourname/submodule.git。

不过,jenkins 中,我使用的是 cd submoduledir && git checkout branch && git pull origin master && cd ../ 。自己去更新 submodule。可能存在更好的方式,以后再看看。

预告:百姓网 陈仓 App 即将出世!诸位敬请期待!

 

自动化测试之六:移动应用测试点整理(转载)

这篇文章对移动 APP 测试点做了一个整理,值得推荐。

作者:

前段时间在weibo上看到有位前辈整理的android测试点,有感而发,结合我们现在的工作,整理了一下经常会遇到的问题。

1.APP基本功能
按照back log整理测试用例,测试中发现有需求变动、或未考虑完全,及时更新测试用例。
测试用例包括:全功能点用例+重点功能快速回归用例 (more…)

创造大于消费,批量创造模式

昨晚看的一篇文章。创造大于消费是成事之本,这也是庞小伟上次说到的生意中的的「生」;而大规模(效率)生产则要做大做广的根本。觉得写程序也一样,为何而写?我想信为写程序而写程序的效率和成交永远都不可能太高。用帮助用户省时间而写,才可能创造出像 Dropbox,gmail 之类的程序,为什么而写从很大程度上决定了写程序得到的收益。为用户功能省时间而写,同时也可以为同事开发效率而写的代码(抽象/模块化)和文档(避免重复沟通)。而自动化则可能大规模生产。一理通百事。很多道理都是想通的,百事,千事,甚至万事。看着邮件,突然觉得可以分享一下这篇文章,因为总有些人把道理用几句话就清楚地说明了。

http://hujinpu.com/the-two-most-important-rules-for-entrepreneurs/

自动化测试之五:iOS 批量打渠道包脚本

我们要提供给各个渠道不用的包,各个包的内容主要是数据统计或者第三方数据统计(如umeng),需要设置不同的 Channel 字符,然后进行打包。

1、需要循环获取渠道内容:

如 channel_list=”abc,def,ghi,jk” 分别获取 abc 及 def 等。

2、需要使用 abc 替换原来的默认 channel 字符

比如:#define kChannelKey                 @”appstore”

我们需要把 appstore 替换为 abc,然后打包。

3、使用命令行打包和签名:

涉及的命令有:agvtool, xcodebuild,xcrun

4、保存ipa包

脚本如下:

#Backup
cp Baixing/Util/BXConfig.h BXConfig.h.bak

#Foreach Channel List
for channel in $(echo $channel_list | tr “,” “\n”)
do
#replace channel
sed “s/@\”appstore\”/@\”$channel\”/” < BXConfig.h.bak > BXConfig.h.bak.2
mv BXConfig.h.bak.2 Baixing/Util/BXConfig.h;

#Clean prev build
rm -rf /Users/Shared/Jenkins/Home/workspace/ios-baixing-ipa/build/Release-iphoneos/

#Starting Build
/usr/bin/xcodebuild -version
AppVer=`/usr/bin/agvtool mvers -terse1`
/usr/bin/xcodebuild -scheme Baixing -sdk iphoneos -workspace Baixing.xcworkspace -configuration “Release” clean build CONFIGURATION_BUILD_DIR=/Users/Shared/Jenkins/Home/workspace/ios-baixing-ipa/build/Release-iphoneos

/usr/bin/xcrun -sdk iphoneos PackageApplication -v /Users/Shared/Jenkins/Home/workspace/ios-baixing-ipa/build/Release-iphoneos/Baixing.app -o /Users/Shared/Jenkins/Home/workspace/ios-baixing-ipa/build/Release-iphoneos/Baixing-Release-${channel}-${AppVer}.ipa –embed ‘”/Users/Shared/Jenkins/Library/MobileDevice/Provisioning Profiles/28096880-AB1B-4E0F-BD68-138C8F9F23EF.mobileprovision”‘

#Save ipa
cp /Users/Shared/Jenkins/Home/workspace/ios-baixing-ipa/build/Release-iphoneos/Baixing-Release-${channel}-${AppVer}.ipa ../release_ipa/Baixing-Release-${channel}-${AppVer}-${BUILD_NUMBER}.ipa

done

 

顺便解决一下 Jenkins 在 mac osx 上执行后 console output 输出中文乱码。

很简单,启动命令行:

JAVA_TOOL_OPTIONS=”-Dfile.encoding=UTF8″ java -jar jenkins.war

是的, JAVA_TOOL_OPTIONS=”-Dfile.encoding=UTF8″ 在java前面。

自动化测试之四:Athrun/iOS之 scroll bug

在 Athrun iOS 框架(感谢太禅同学),UIATarget.localTarget().dragFromToForDuration 运行在 iOS 5.1 会出现错误,如下:
An error occurred while trying to run the script

开始以为是 instruments 本身的 bug。经过验证,发现简单的 dragFromToForDuration 是可以跑的。本人用最笨的排除法,发现去掉在 athrunImports.js 文件里面去掉 json.js 的引用,即告正常。

看来是 json.js 有问题,因为经过搜索发现 json 没有地方在引用他,所以就简单的删除/注释掉。暂时不理会它,有兴趣的时候回头来看。呵呵。哪位有兴趣可以先研究一下 json.js 有何问题。

 

 

自动化测试之三: Junit reports + 附件

我们使用  Jenkins 来持续集成 iOS app。使用 jenkins 的命令行工具来启动 iOS Instruments Automation 自动执行测试用例(就是淘宝 Athrun的 AppTest.sh)。

不过这有个问题,就是 Junit 生成的 Test Reuslts 报告很不满意,怎么办,就自己改造吧。

但是不想动 Athrun,所以就自己弄几个脚本来做这个事情(当然也简化一下 AppTest.sh,呵呵,主要是让 Instruments.trace 文件能遵守某个规则,比如原来的是 InstrumentscliNNNN.trace,我们现在改为 testCaseName.js.trace,这样方便脚本处理)。

我们从 Athurn 产生的 Junit reports XML(以下简称原XML)开始。

这个脚本,首先把 原XML 的 “iphone auto test” 修改为 “iphoneTest” + build_Number。这样做的是为了产生唯一的附件目录,这样一次testcase有一个附件目录,不然的话,很多附件在一个目录就无法搞清楚本次失败的附件是那几个文件?

第二、把失败的测试用例的 testCaseName.js.trace 打包的zip,放到目录 iphoneTest${build_Number}。比如 iphoneTest1。

第一和第二结合,就能成功看到失败测试用例的附件了。

第三、原XML 的 caseStep 加个“\n”,方便人能看。一行一行的看的清楚啊。

Jenkins JUnit reports 使用替换后的 XML即可。

下面 AppTest.sh 和 对 原 XML 进行处理的脚本,请大家参考,欢迎提出意见。

AppTest.sh

get_err_trace.php

 

补充:关于第二步,在 Jenkins 上面 shell

cd  /someDir/athrun/; #Athrun 目录
php get_err_trace.php ${BUILD_NUMBER} traces/;

cd buildDir/;  #build workspace 目录
mkdir ios-test-reports/iphoneTest${BUILD_NUMBER}/
mkdir ../ios-test-reports/iphoneTest${BUILD_NUMBER}/

echo “” > ../traces/temp.js.trace.${BUILD_NUMBER}.zip;  #这个,简单的弄一个 zip,免的 cp 出现 no such file or Directory,我偷懒点,呵呵,当然可以有更优雅的办法。
cp -f ../traces/*.js.trace.${BUILD_NUMBER}.zip “ios-test-reports/iphoneTest${BUILD_NUMBER}/”;

#复制 error trace zip
cp -f ../traces/*.js.trace.${BUILD_NUMBER}.zip ../ios-test-reports/iphoneTest${BUILD_NUMBER}/

#清理不需要的zip
rm -f ../traces/temp.js.trace.${BUILD_NUMBER}.zip
rm -f ios-test-reports/iphoneTest${BUILD_NUMBER}/temp.js.trace.${BUILD_NUMBER}.zip

cp -f /Athrun/log/log.trace.xml ios-test-reports/log.xml;

#ios-test-reports 目录就是 Jenkins上 JUnit reports 设置的目录

Test report XMLs:ios-test-reports/log.xml

Publish test attachments: Checked